From 351c5f1cd5bb2ccd5695c22b84e4ec854924580e Mon Sep 17 00:00:00 2001 From: Adarsh Jha <31096082+adarshjhaa100@users.noreply.github.com> Date: Tue, 31 Oct 2023 22:18:49 +0530 Subject: [PATCH] feat: modified choice input to take option list opposed to blank text (#8180) --- pkg/cmd/workflow/run/run.go | 21 ++++- pkg/cmd/workflow/run/run_test.go | 132 +++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 2 deletions(-) diff --git a/pkg/cmd/workflow/run/run.go b/pkg/cmd/workflow/run/run.go index 009c48182..86b24ed64 100644 --- a/pkg/cmd/workflow/run/run.go +++ b/pkg/cmd/workflow/run/run.go @@ -217,7 +217,18 @@ func collectInputs(p iprompter, yamlContent []byte) (map[string]string, error) { for _, input := range inputs { var answer string - if input.Required { + + if input.Type == "choice" { + name := input.Name + if input.Required { + name += " (required)" + } + selected, err := p.Select(name, input.Default, input.Options) + if err != nil { + return nil, err + } + answer = input.Options[selected] + } else if input.Required { for answer == "" { answer, err = p.Input(input.Name+" (required)", input.Default) if err != nil { @@ -234,7 +245,6 @@ func collectInputs(p iprompter, yamlContent []byte) (map[string]string, error) { providedInputs[input.Name] = answer } - return providedInputs, nil } @@ -331,6 +341,8 @@ type WorkflowInput struct { Required bool Default string Description string + Type string + Options []string } func findInputs(yamlContent []byte) ([]WorkflowInput, error) { @@ -412,11 +424,16 @@ func findInputs(yamlContent []byte) ([]WorkflowInput, error) { } for name, input := range m { + if input.Type == "choice" && len(input.Options) == 0 { + return nil, fmt.Errorf("workflow input %q is of type choice, but has no options", name) + } out = append(out, WorkflowInput{ Name: name, Default: input.Default, Description: input.Description, Required: input.Required, + Options: input.Options, + Type: input.Type, }) } diff --git a/pkg/cmd/workflow/run/run_test.go b/pkg/cmd/workflow/run/run_test.go index 70fea8aa7..ee1bc5a1e 100644 --- a/pkg/cmd/workflow/run/run_test.go +++ b/pkg/cmd/workflow/run/run_test.go @@ -350,6 +350,50 @@ jobs: encodedYAMLContent := base64.StdEncoding.EncodeToString(yamlContent) + yamlContentChoiceIp := []byte(` +name: choice inputs +on: + workflow_dispatch: + inputs: + name: + type: choice + description: Who to greet + default: monalisa + options: + - monalisa + - cschleiden + favourite-animal: + type: choice + description: What's your favourite animal + required: true + options: + - dog + - cat +jobs: + greet: + runs-on: ubuntu-latest + steps: + - name: Send greeting + run: echo "${{ github.event.inputs.message }} ${{ fromJSON('["", "🥳"]')[github.event.inputs.use-emoji == 'true'] }} ${{ github.event.inputs.name }}"`) + encodedYAMLContentChoiceIp := base64.StdEncoding.EncodeToString(yamlContentChoiceIp) + + yamlContentMissingChoiceIp := []byte(` +name: choice missing inputs +on: + workflow_dispatch: + inputs: + name: + type: choice + description: Who to greet + options: +jobs: + greet: + runs-on: ubuntu-latest + steps: + - name: Send greeting + run: echo "${{ github.event.inputs.message }} ${{ fromJSON('["", "🥳"]')[github.event.inputs.use-emoji == 'true'] }} ${{ github.event.inputs.name }}"`) + encodedYAMLContentMissingChoiceIp := base64.StdEncoding.EncodeToString(yamlContentMissingChoiceIp) + stubs := func(reg *httpmock.Registry) { reg.Register( httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/workflow.yml"), @@ -640,6 +684,94 @@ jobs: }, wantOut: "✓ Created workflow_dispatch event for workflow.yml at trunk\n\nTo see runs for this workflow, try: gh run list --workflow=workflow.yml\n", }, + { + name: "prompt, workflow choice input", + tty: true, + opts: &RunOptions{ + Prompt: true, + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register( + httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"), + httpmock.JSONResponse(shared.WorkflowsPayload{ + Workflows: []shared.Workflow{ + { + Name: "choice inputs", + ID: 12345, + State: shared.Active, + Path: ".github/workflows/workflow.yml", + }, + }, + })) + reg.Register( + httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/workflow.yml"), + httpmock.JSONResponse(struct{ Content string }{ + Content: encodedYAMLContentChoiceIp, + })) + reg.Register( + httpmock.REST("POST", "repos/OWNER/REPO/actions/workflows/12345/dispatches"), + httpmock.StatusStringResponse(204, "cool")) + }, + promptStubs: func(pm *prompter.MockPrompter) { + pm.RegisterSelect("Select a workflow", []string{"choice inputs (workflow.yml)"}, func(_, _ string, opts []string) (int, error) { + return 0, nil + }) + pm.RegisterSelect("favourite-animal (required)", []string{"dog", "cat"}, func(_, _ string, opts []string) (int, error) { + return 0, nil + }) + pm.RegisterSelect("name", []string{"monalisa", "cschleiden"}, func(_, _ string, opts []string) (int, error) { + return 0, nil + }) + + }, + wantBody: map[string]interface{}{ + "inputs": map[string]interface{}{ + "name": "monalisa", + "favourite-animal": "dog", + }, + "ref": "trunk", + }, + wantOut: "✓ Created workflow_dispatch event for workflow.yml at trunk\n\nTo see runs for this workflow, try: gh run list --workflow=workflow.yml\n", + }, + { + name: "prompt, workflow choice missing input", + tty: true, + opts: &RunOptions{ + Prompt: true, + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register( + httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows"), + httpmock.JSONResponse(shared.WorkflowsPayload{ + Workflows: []shared.Workflow{ + { + Name: "choice missing inputs", + ID: 12345, + State: shared.Active, + Path: ".github/workflows/workflow.yml", + }, + }, + })) + reg.Register( + httpmock.REST("GET", "repos/OWNER/REPO/contents/.github/workflows/workflow.yml"), + httpmock.JSONResponse(struct{ Content string }{ + Content: encodedYAMLContentMissingChoiceIp, + })) + reg.Register( + httpmock.REST("POST", "repos/OWNER/REPO/actions/workflows/12345/dispatches"), + httpmock.StatusStringResponse(204, "cool")) + }, + promptStubs: func(pm *prompter.MockPrompter) { + pm.RegisterSelect("Select a workflow", []string{"choice missing inputs (workflow.yml)"}, func(_, _ string, opts []string) (int, error) { + return 0, nil + }) + pm.RegisterSelect("name", []string{}, func(_, _ string, opts []string) (int, error) { + return 0, nil + }) + }, + wantErr: true, + errOut: "workflow input \"name\" is of type choice, but has no options", + }, } for _, tt := range tests {