Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions internal/temporalcli/commands.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,7 @@ func NewTemporalScheduleCommand(cctx *CommandContext, parent *TemporalCommand) *
s.Command.AddCommand(&NewTemporalScheduleDeleteCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalScheduleDescribeCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalScheduleListCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalScheduleListMatchingTimesCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalScheduleToggleCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalScheduleTriggerCommand(cctx, &s).Command)
s.Command.AddCommand(&NewTemporalScheduleUpdateCommand(cctx, &s).Command)
Expand Down Expand Up @@ -2270,6 +2271,39 @@ func NewTemporalScheduleListCommand(cctx *CommandContext, parent *TemporalSchedu
return &s
}

type TemporalScheduleListMatchingTimesCommand struct {
Parent *TemporalScheduleCommand
Command cobra.Command
ScheduleIdOptions
StartTime cliext.FlagTimestamp
EndTime cliext.FlagTimestamp
}

func NewTemporalScheduleListMatchingTimesCommand(cctx *CommandContext, parent *TemporalScheduleCommand) *TemporalScheduleListMatchingTimesCommand {
var s TemporalScheduleListMatchingTimesCommand
s.Parent = parent
s.Command.DisableFlagsInUseLine = true
s.Command.Use = "list-matching-times [flags]"
s.Command.Short = "List matching times for a Schedule (Experimental)"
if hasHighlighting {
s.Command.Long = "\nNote: This is an experimental feature and may change in the future.\n\nList the times a Schedule would fire within a given time range.\nUse this command to preview when a Schedule will trigger Workflow\nExecutions without actually running them.\n\nFor example:\n\n\x1b[1m temporal schedule list-matching-times \\\n --schedule-id \"YourScheduleId\" \\\n --start-time \"2024-01-01T00:00:00Z\" \\\n --end-time \"2024-01-31T23:59:59Z\"\x1b[0m"
} else {
s.Command.Long = "\nNote: This is an experimental feature and may change in the future.\n\nList the times a Schedule would fire within a given time range.\nUse this command to preview when a Schedule will trigger Workflow\nExecutions without actually running them.\n\nFor example:\n\n```\n temporal schedule list-matching-times \\\n --schedule-id \"YourScheduleId\" \\\n --start-time \"2024-01-01T00:00:00Z\" \\\n --end-time \"2024-01-31T23:59:59Z\"\n```"
}
s.Command.Args = cobra.NoArgs
s.Command.Flags().Var(&s.StartTime, "start-time", "Start of time range to list matching times. Required.")
_ = cobra.MarkFlagRequired(s.Command.Flags(), "start-time")
s.Command.Flags().Var(&s.EndTime, "end-time", "End of time range to list matching times. Required.")
_ = cobra.MarkFlagRequired(s.Command.Flags(), "end-time")
s.ScheduleIdOptions.BuildFlags(s.Command.Flags())
s.Command.Run = func(c *cobra.Command, args []string) {
if err := s.run(cctx, args); err != nil {
cctx.Options.Fail(err)
}
}
return &s
}

type TemporalScheduleToggleCommand struct {
Parent *TemporalScheduleCommand
Command cobra.Command
Expand Down
56 changes: 52 additions & 4 deletions internal/temporalcli/commands.schedule.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package temporalcli

import (
"encoding/json"
"errors"
"fmt"
"regexp"
Expand All @@ -11,10 +12,12 @@ import (
"github.com/temporalio/cli/cliext"
"github.com/temporalio/cli/internal/printer"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/timestamppb"

commonpb "go.temporal.io/api/common/v1"
enumspb "go.temporal.io/api/enums/v1"
schedpb "go.temporal.io/api/schedule/v1"
"go.temporal.io/api/temporalproto"
"go.temporal.io/api/workflowservice/v1"
"go.temporal.io/sdk/client"
)
Expand Down Expand Up @@ -47,8 +50,8 @@ type printableSchedule struct {
LastUpdateAt time.Time `cli:",cardOmitEmpty"` // describe only
ActionCounts *actionCounts `cli:",cardOmitEmpty"` // describe only
// SearchAttributes, Memo
SearchAttributes *commonpb.SearchAttributes `cli:",cardOmitEmpty"`
Memo *commonpb.Memo `cli:",cardOmitEmpty"`
SearchAttributes map[string]interface{} `cli:",cardOmitEmpty"`
Memo *commonpb.Memo `cli:",cardOmitEmpty"`
}

type actionCounts struct {
Expand All @@ -68,7 +71,7 @@ func describeResultToPrintable(id string, desc *client.ScheduleDescription) *pri
// ID, SearchAttributes, Memo
out := &printableSchedule{
ScheduleId: id,
SearchAttributes: desc.SearchAttributes,
SearchAttributes: searchAttributesToMap(desc.SearchAttributes),
Memo: desc.Memo,
}
// Schedule.Action
Expand Down Expand Up @@ -113,7 +116,7 @@ func listEntryToPrintable(ent *client.ScheduleListEntry) *printableSchedule {
Paused: ent.Paused,
Notes: ent.Note,
Action: struct{ Workflow string }{Workflow: ent.WorkflowType.Name},
SearchAttributes: ent.SearchAttributes,
SearchAttributes: searchAttributesToMap(ent.SearchAttributes),
Memo: ent.Memo,
}
specToPrintable(out, ent.Spec)
Expand Down Expand Up @@ -606,3 +609,48 @@ func formatDuration(d time.Duration) string {
s = strings.TrimSpace(s)
return s
}

func (c *TemporalScheduleListMatchingTimesCommand) run(cctx *CommandContext, args []string) error {
cl, err := dialClient(cctx, &c.Parent.ClientOptions)
if err != nil {
return err
}
defer cl.Close()

res, err := cl.WorkflowService().ListScheduleMatchingTimes(cctx, &workflowservice.ListScheduleMatchingTimesRequest{
Namespace: c.Parent.Namespace,
ScheduleId: c.ScheduleId,
StartTime: timestamppb.New(c.StartTime.Time()),
EndTime: timestamppb.New(c.EndTime.Time()),
})
if err != nil {
return err
}

cctx.Printer.StartList()
defer cctx.Printer.EndList()

for _, t := range res.StartTime {
cctx.Printer.Printlnf("%v", t.AsTime())
}

return nil
}

func searchAttributesToMap(sa *commonpb.SearchAttributes) map[string]interface{} {
// Step 1 — handle nil
if sa == nil {
return nil
}
// Step 2 — marshal to JSON bytes using proto marshaler
b, err := temporalproto.CustomJSONMarshalOptions{}.Marshal(sa)
if err != nil {
return nil
}
// Step 3 — unmarshal bytes into plain map
var m map[string]interface{}
if err := json.Unmarshal(b, &m); err != nil {
return nil
}
return m
}
30 changes: 30 additions & 0 deletions internal/temporalcli/commands.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2320,6 +2320,36 @@ commands:
- overlap-policy
- schedule-id

- name: temporal schedule list-matching-times
summary: List matching times for a Schedule (Experimental)
description: |

Note: This is an experimental feature and may change in the future.

List the times a Schedule would fire within a given time range.
Use this command to preview when a Schedule will trigger Workflow
Executions without actually running them.

For example:

```
temporal schedule list-matching-times \
--schedule-id "YourScheduleId" \
--start-time "2024-01-01T00:00:00Z" \
--end-time "2024-01-31T23:59:59Z"
```
options:
- name: start-time
type: timestamp
description: Start of time range to list matching times.
required: true
- name: end-time
type: timestamp
description: End of time range to list matching times.
required: true
option-sets:
- schedule-id

- name: temporal schedule create
summary: Create a new Schedule
description: |
Expand Down