Skip to content

Commit 1f63231

Browse files
authored
Normalize --name and --type flags on workflow commands (#580)
Fixes #475
1 parent 06af16e commit 1f63231

8 files changed

Lines changed: 129 additions & 53 deletions

File tree

temporalcli/commands.gen.go

Lines changed: 52 additions & 37 deletions
Large diffs are not rendered by default.

temporalcli/commands.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,15 @@ func writeEnvConfigFile(file string, env map[string]map[string]string) error {
499499
return nil
500500
}
501501

502+
func aliasNormalizer(aliases map[string]string) func(f *pflag.FlagSet, name string) pflag.NormalizedName {
503+
return func(f *pflag.FlagSet, name string) pflag.NormalizedName {
504+
if actual := aliases[name]; actual != "" {
505+
name = actual
506+
}
507+
return pflag.NormalizedName(name)
508+
}
509+
}
510+
502511
func newNopLogger() *slog.Logger { return slog.New(discardLogHandler{}) }
503512

504513
type discardLogHandler struct{}

temporalcli/commands.workflow.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func (c *TemporalWorkflowDeleteCommand) run(cctx *CommandContext, args []string)
8484

8585
func (c *TemporalWorkflowQueryCommand) run(cctx *CommandContext, args []string) error {
8686
return queryHelper(cctx, c.Parent, c.PayloadInputOptions,
87-
c.Type, c.RejectCondition, c.WorkflowReferenceOptions)
87+
c.Name, c.RejectCondition, c.WorkflowReferenceOptions)
8888
}
8989

9090
func (c *TemporalWorkflowSignalCommand) run(cctx *CommandContext, args []string) error {

temporalcli/commands.workflow_exec_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ func (s *SharedServerSuite) TestWorkflow_Start_SimpleSuccess() {
5555
"-o", "json",
5656
"--address", s.Address(),
5757
"--task-queue", s.Worker().Options.TaskQueue,
58-
"--type", "DevWorkflow",
58+
// Use --name here to make sure the alias works
59+
"--name", "DevWorkflow",
5960
"--workflow-id", "my-id2",
6061
)
6162
s.NoError(res.Err)

temporalcli/commands.workflow_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ func (s *SharedServerSuite) testSignalBatchWorkflow(json bool) *CommandResult {
9999
"workflow", "signal",
100100
"--address", s.Address(),
101101
"--query", "CustomKeywordField = '" + searchAttr + "'",
102-
"--name", "my-signal",
102+
// Use --type here to make sure the alias works
103+
"--type", "my-signal",
103104
"-i", `{"key": "val"}`,
104105
}
105106
if json {
@@ -421,12 +422,15 @@ func (s *SharedServerSuite) TestWorkflow_Update() {
421422
}()
422423

423424
// successful update, should show the result
424-
res := s.Execute("workflow", "update", "--address", s.Address(), "-w", run.GetID(), "--name", updateName, "-i", strconv.Itoa(input))
425+
res := s.Execute("workflow", "update", "--address", s.Address(), "-w", run.GetID(),
426+
"--name", updateName, "-i", strconv.Itoa(input))
425427
s.NoError(res.Err)
426428
s.Contains(res.Stdout.String(), strconv.Itoa(input))
427429

428430
// successful update passing first-execution-run-id
429-
res = s.Execute("workflow", "update", "--address", s.Address(), "-w", run.GetID(), "--name", updateName, "-i", strconv.Itoa(input), "--first-execution-run-id", run.GetRunID())
431+
res = s.Execute("workflow", "update", "--address", s.Address(), "-w", run.GetID(),
432+
// Use --type here to make sure the alias works
433+
"--type", updateName, "-i", strconv.Itoa(input), "--first-execution-run-id", run.GetRunID())
430434
s.NoError(res.Err)
431435

432436
// successful update passing update-id
@@ -556,7 +560,7 @@ func (s *SharedServerSuite) testQueryWorkflow(json bool) {
556560
"workflow", "query",
557561
"--address", s.Address(),
558562
"-w", run.GetID(),
559-
"--type", "my-query",
563+
"--name", "my-query",
560564
"-i", `"hi"`,
561565
}
562566
if json {
@@ -580,6 +584,7 @@ func (s *SharedServerSuite) testQueryWorkflow(json bool) {
580584
"workflow", "query",
581585
"--address", s.Address(),
582586
"-w", run.GetID(),
587+
// Use --type here to make sure the alias works
583588
"--type", "my-query",
584589
"-i", `"hi"`,
585590
"--reject-condition", "not_open",

temporalcli/commandsmd/code.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,17 +208,51 @@ func (c *Command) writeCode(w *codeWriter) error {
208208
// If there are subcommands, this needs to be persistent flags
209209
flagVar = "s.Command.PersistentFlags()"
210210
}
211+
var flagAliases [][]string
211212
for _, optSet := range c.OptionsSets {
213+
// Add aliases
214+
for _, opt := range optSet.Options {
215+
for _, alias := range opt.Aliases {
216+
flagAliases = append(flagAliases, []string{alias, opt.Name})
217+
}
218+
}
219+
for _, include := range optSet.IncludeOptionsSets {
220+
// Find include
221+
cmdLoop:
222+
for _, cmd := range w.allCommands {
223+
for _, optSet := range cmd.OptionsSets {
224+
if optSet.SetName == include {
225+
for _, opt := range optSet.Options {
226+
for _, alias := range opt.Aliases {
227+
flagAliases = append(flagAliases, []string{alias, opt.Name})
228+
}
229+
}
230+
break cmdLoop
231+
}
232+
}
233+
}
234+
}
235+
212236
// If there's a name, this is done in the method
213237
if optSet.SetName != "" {
214238
w.writeLinef("s.%v.buildFlags(cctx, %v)", optSet.setStructName(), flagVar)
215239
continue
216240
}
241+
217242
// Each field
218243
if err := optSet.writeFlagBuilding("s", flagVar, w); err != nil {
219244
return fmt.Errorf("failed building option flags: %w", err)
220245
}
221246
}
247+
// Generate normalize for aliases
248+
if len(flagAliases) > 0 {
249+
sort.Slice(flagAliases, func(i, j int) bool { return flagAliases[i][0] < flagAliases[j][0] })
250+
w.writeLinef("%v.SetNormalizeFunc(aliasNormalizer(map[string]string{", flagVar)
251+
for _, aliases := range flagAliases {
252+
w.writeLinef("%q: %q,", aliases[0], aliases[1])
253+
}
254+
w.writeLinef("}))")
255+
}
222256
// If there are no subcommands, we need a run function
223257
if len(subCommands) == 0 {
224258
w.writeLinef("s.Command.Run = func(c *%v.Command, args []string) {", w.importCobra())
@@ -339,17 +373,25 @@ func (c *CommandOption) writeFlagBuilding(selfVar, flagVar string, w *codeWriter
339373
if len(c.EnumValues) > 0 {
340374
desc += fmt.Sprintf(" Accepted values: %s.", strings.Join(c.EnumValues, ", "))
341375
}
376+
// If required, append to desc
377+
if c.Required {
378+
desc += " Required."
379+
}
380+
// If there are aliases, append to desc
381+
for _, alias := range c.Aliases {
382+
desc += fmt.Sprintf(` Aliased as "--%v".`, alias)
383+
}
342384

343385
if setDefault != "" {
344386
// set default before calling Var so that it stores thedefault value into the flag
345387
w.writeLinef("%v.%v = %v", selfVar, c.fieldName(), setDefault)
346388
}
347-
if c.Alias == "" {
389+
if c.Shorthand == "" {
348390
w.writeLinef("%v.%v(&%v.%v, %q%v, %q)",
349391
flagVar, flagMeth, selfVar, c.fieldName(), c.Name, defaultLit, desc)
350392
} else {
351393
w.writeLinef("%v.%vP(&%v.%v, %q, %q%v, %q)",
352-
flagVar, flagMeth, selfVar, c.fieldName(), c.Name, c.Alias, defaultLit, desc)
394+
flagVar, flagMeth, selfVar, c.fieldName(), c.Name, c.Shorthand, defaultLit, desc)
353395
}
354396
if c.Required {
355397
w.writeLinef("_ = %v.MarkFlagRequired(%v, %q)", w.importCobra(), flagVar, c.Name)

temporalcli/commandsmd/commands.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ This document has a specific structure used by a parser. Here are the rules:
2828
* `Default: <default-value>.` - Sets the default value of the option. No default means zero value of the type.
2929
* `Options: <option>, <option>.` - Sets the possible options for a string enum type.
3030
* `Env: <env-var>.` - Binds the environment variable to this flag.
31+
* ``Alias: `--<alias>`.`` - Sets a flag as an alias of this one. The flag should not be separately defined.
3132
* Options should be in order of most commonly used.
3233
* Also can have single lines below options that say
3334
`Includes options set for [<options-set-name>](#options-set-for-<options-set-link-name>).` which is the equivalent
@@ -879,7 +880,7 @@ Use the options listed below to change the command's behavior.
879880

880881
#### Options
881882

882-
* `--type` (string) - Query Type/Name. Required.
883+
* `--name` (string) - Query Type/Name. Required. Alias: `--type`.
883884
* `--reject-condition` (string-enum) - Optional flag for rejecting Queries based on Workflow state.
884885
Options: not_open, not_completed_cleanly.
885886

@@ -950,7 +951,7 @@ Use the options listed below to change the command's behavior.
950951

951952
#### Options
952953

953-
* `--name` (string) - Signal Name. Required.
954+
* `--name` (string) - Signal Name. Required. Alias: `--type`.
954955

955956
Includes options set for [payload input](#options-set-for-payload-input).
956957

@@ -1000,7 +1001,7 @@ temporal workflow start \
10001001
#### Options set for shared workflow start:
10011002

10021003
* `--workflow-id`, `-w` (string) - Workflow Id.
1003-
* `--type` (string) - Workflow Type name. Required.
1004+
* `--type` (string) - Workflow Type name. Required. Alias: `--name`.
10041005
* `--task-queue`, `-t` (string) - Workflow Task queue. Required.
10051006
* `--run-timeout` (duration) - Timeout of a Workflow Run.
10061007
* `--execution-timeout` (duration) - Timeout for a WorkflowExecution, including retries and ContinueAsNew tasks.
@@ -1087,7 +1088,7 @@ Use the options listed below to change the command's behavior.
10871088

10881089
#### Options
10891090

1090-
* `--name` (string) - Update Name. Required.
1091+
* `--name` (string) - Update Name. Required. Alias: `--type`.
10911092
* `--workflow-id`, `-w` (string) - Workflow Id. Required.
10921093
* `--update-id` (string) - Update ID. If unset, default to a UUID.
10931094
* `--run-id`, `-r` (string) - Run Id. If unset, the currently running Workflow Execution receives the Update.

temporalcli/commandsmd/parse.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@ type CommandOptions struct {
3737

3838
type CommandOption struct {
3939
Name string
40-
Alias string
40+
Shorthand string
4141
DataType string
4242
Desc string
4343
Required bool
4444
DefaultValue string
4545
EnumValues []string
4646
EnvVar string
47+
Aliases []string
4748
}
4849

4950
func ParseMarkdownCommands() ([]*Command, error) {
@@ -229,16 +230,16 @@ func (c *CommandOption) parseBulletLine(bullet string) error {
229230
c.Name = strings.TrimPrefix(bullet[:tickEnd], "--")
230231
bullet = strings.TrimSpace(bullet[tickEnd+1:])
231232

232-
// Alias
233+
// Shorthand
233234
if strings.HasPrefix(bullet, ", `") {
234235
bullet = strings.TrimPrefix(bullet, ", `")
235236
tickEnd = strings.Index(bullet, "`")
236237
if tickEnd == -1 {
237238
return fmt.Errorf("missing ending backtick")
238239
} else if !strings.HasPrefix(bullet, "-") {
239-
return fmt.Errorf("option alias %q does not have leading '-'", bullet[:tickEnd])
240+
return fmt.Errorf("option shorthand %q does not have leading '-'", bullet[:tickEnd])
240241
}
241-
c.Alias = strings.TrimPrefix(bullet[:tickEnd], "-")
242+
c.Shorthand = strings.TrimPrefix(bullet[:tickEnd], "-")
242243
bullet = strings.TrimSpace(bullet[tickEnd+1:])
243244
}
244245

@@ -276,6 +277,8 @@ func (c *CommandOption) parseBulletLine(bullet string) error {
276277
c.EnumValues = strings.Split(strings.TrimPrefix(lastSentence, "Options: "), ", ")
277278
case strings.HasPrefix(lastSentence, "Env: "):
278279
c.EnvVar = strings.TrimPrefix(lastSentence, "Env: ")
280+
case strings.HasPrefix(lastSentence, "Alias: `--"):
281+
c.Aliases = append(c.Aliases, strings.TrimSuffix(strings.TrimPrefix(lastSentence, "Alias: `--"), "`"))
279282
default:
280283
return nil
281284
}

0 commit comments

Comments
 (0)