@@ -11,6 +11,7 @@ import (
1111 compinternal "github.com/algolia/cli/pkg/cmd/compositions/internal"
1212 "github.com/algolia/cli/pkg/cmdutil"
1313 "github.com/algolia/cli/pkg/config"
14+ "github.com/algolia/cli/pkg/interactive"
1415 "github.com/algolia/cli/pkg/iostreams"
1516 "github.com/algolia/cli/pkg/validators"
1617)
@@ -20,8 +21,10 @@ type UpsertOptions struct {
2021 Config config.IConfig
2122 IO * iostreams.IOStreams
2223 CompositionClient func () (* algoliaComposition.APIClient , error )
24+ Prompter interactive.Prompter
2325 CompositionID string
2426 File string
27+ Interactive bool
2528 PrintFlags * cmdutil.PrintFlags
2629}
2730
@@ -31,6 +34,7 @@ func NewUpsertCmd(f *cmdutil.Factory) *cobra.Command {
3134 IO : f .IOStreams ,
3235 Config : f .Config ,
3336 CompositionClient : f .CompositionClient ,
37+ Prompter : f .Prompter ,
3438 PrintFlags : cmdutil .NewPrintFlags ().WithDefaultOutput ("json" ),
3539 }
3640
@@ -47,29 +51,63 @@ func NewUpsertCmd(f *cmdutil.Factory) *cobra.Command {
4751
4852 # Upsert from stdin
4953 $ cat body.json | algolia compositions upsert my-comp --file -
54+
55+ # Build a composition interactively
56+ $ algolia compositions upsert my-comp --interactive
5057 ` ),
5158 RunE : func (cmd * cobra.Command , args []string ) error {
5259 opts .CompositionID = args [0 ]
60+
61+ if opts .Interactive == (opts .File != "" ) {
62+ return cmdutil .FlagErrorf ("exactly one of `--file` or `--interactive` is required" )
63+ }
64+ if opts .Interactive && ! opts .IO .CanPrompt () {
65+ return cmdutil .FlagErrorf ("`--interactive` requires a terminal; use `--file` instead" )
66+ }
67+
5368 return runUpsertCmd (opts )
5469 },
5570 }
5671
5772 cmd .Flags ().StringVarP (& opts .File , "file" , "f" , "" , "JSON file path (use - for stdin)" )
58- _ = cmd .MarkFlagRequired ( "file " )
73+ cmd .Flags (). BoolVarP ( & opts . Interactive , "interactive" , "i" , false , "Build the composition interactively " )
5974
6075 opts .PrintFlags .AddFlags (cmd )
6176 return cmd
6277}
6378
64- func runUpsertCmd (opts * UpsertOptions ) error {
79+ // buildComposition produces the composition body either interactively or by
80+ // reading and parsing the JSON file.
81+ func buildComposition (opts * UpsertOptions ) (algoliaComposition.Composition , error ) {
82+ var comp algoliaComposition.Composition
83+
84+ if opts .Interactive {
85+ comp .ObjectID = opts .CompositionID
86+ prompter := opts .Prompter
87+ if prompter == nil {
88+ prompter = interactive .NewSurveyPrompter (opts .IO )
89+ }
90+ builder := & interactive.Builder {Prompter : prompter }
91+ if err := builder .Build (& comp ); err != nil {
92+ return comp , fmt .Errorf ("building composition: %w" , err )
93+ }
94+ return comp , nil
95+ }
96+
6597 raw , err := cmdutil .ReadFile (opts .File , opts .IO .In )
6698 if err != nil {
67- return fmt .Errorf ("reading file: %w" , err )
99+ return comp , fmt .Errorf ("reading file: %w" , err )
68100 }
69-
70- var comp algoliaComposition.Composition
71101 if err := json .Unmarshal (raw , & comp ); err != nil {
72- return fmt .Errorf ("parsing composition JSON: %w" , err )
102+ return comp , fmt .Errorf ("parsing composition JSON: %w" , err )
103+ }
104+ return comp , nil
105+ }
106+
107+ func runUpsertCmd (opts * UpsertOptions ) error {
108+ comp , err := buildComposition (opts )
109+ if err != nil {
110+ return err
73111 }
74112
75113 client , err := opts .CompositionClient ()
0 commit comments