diff --git a/internal/cli/actions.go b/internal/cli/actions.go index a94f71653..a73019cf4 100644 --- a/internal/cli/actions.go +++ b/internal/cli/actions.go @@ -419,7 +419,7 @@ func deployActionCmd(cli *cli) *cobra.Command { auth0 actions deploy --json`, RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { - if err := actionID.Pick(cmd, &inputs.ID, cli.actionPickerOptions); err != nil { + if err := actionID.Pick(cmd, &inputs.ID, cli.undeployedActionPickerOptions); err != nil { return err } } else { @@ -498,6 +498,26 @@ func (c *cli) actionPickerOptions(ctx context.Context) (pickerOptions, error) { return opts, nil } +func (c *cli) undeployedActionPickerOptions(ctx context.Context) (pickerOptions, error) { + list, err := c.api.Action.List(ctx, management.Parameter("deployed", "false")) + if err != nil { + return nil, err + } + + var opts pickerOptions + for _, r := range list.Actions { + label := fmt.Sprintf("%s %s", r.GetName(), ansi.Faint("("+r.GetID()+")")) + + opts = append(opts, pickerOption{value: r.GetID(), label: label}) + } + + if len(opts) == 0 { + return nil, errors.New("There are currently no actions to deploy.") + } + + return opts, nil +} + func (c *cli) actionEditorHint() { c.renderer.Infof("%s Once you close the editor, the action will be saved. To cancel, press CTRL+C.", ansi.Faint("Hint:")) } diff --git a/internal/cli/actions_test.go b/internal/cli/actions_test.go index a091703cf..dee12f61b 100644 --- a/internal/cli/actions_test.go +++ b/internal/cli/actions_test.go @@ -211,6 +211,85 @@ func TestActionsPickerOptions(t *testing.T) { } } +func TestUndeployedActionsPickerOptions(t *testing.T) { + tests := []struct { + name string + actions []*management.Action + apiError error + assertOutput func(t testing.TB, options pickerOptions) + assertError func(t testing.TB, err error) + }{ + { + name: "happy path", + actions: []*management.Action{ + { + ID: auth0.String("some-id-1"), + Name: auth0.String("some-name-1"), + }, + { + ID: auth0.String("some-id-2"), + Name: auth0.String("some-name-2"), + }, + }, + assertOutput: func(t testing.TB, options pickerOptions) { + assert.Len(t, options, 2) + assert.Equal(t, "some-name-1 (some-id-1)", options[0].label) + assert.Equal(t, "some-id-1", options[0].value) + assert.Equal(t, "some-name-2 (some-id-2)", options[1].label) + assert.Equal(t, "some-id-2", options[1].value) + }, + assertError: func(t testing.TB, err error) { + t.Fail() + }, + }, + { + name: "no actions", + actions: []*management.Action{}, + assertOutput: func(t testing.TB, options pickerOptions) { + t.Fail() + }, + assertError: func(t testing.TB, err error) { + assert.ErrorContains(t, err, "There are currently no actions to deploy.") + }, + }, + { + name: "API error", + apiError: errors.New("error"), + assertOutput: func(t testing.TB, options pickerOptions) { + t.Fail() + }, + assertError: func(t testing.TB, err error) { + assert.Error(t, err) + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + actionAPI := mock.NewMockActionAPI(ctrl) + actionAPI.EXPECT(). + List(gomock.Any(), gomock.Any()). + Return(&management.ActionList{ + Actions: test.actions}, test.apiError) + + cli := &cli{ + api: &auth0.API{Action: actionAPI}, + } + + options, err := cli.undeployedActionPickerOptions(context.Background()) + + if err != nil { + test.assertError(t, err) + } else { + test.assertOutput(t, options) + } + }) + } +} + func TestActionsInputSecretsToActionSecrets(t *testing.T) { t.Run("it should map input secrets to action payload", func(t *testing.T) { input := map[string]string{