From ab381649da05a391005af122e45452aae0ca937d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 3 Oct 2024 02:56:58 +0000 Subject: [PATCH] Add parsing for workflow dispatch (#118) Reviewed-on: https://gitea.com/gitea/act/pulls/118 --- pkg/jobparser/model.go | 77 ++++++++++++++++++++++++++++++++++--- pkg/jobparser/model_test.go | 57 ++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 7 deletions(-) diff --git a/pkg/jobparser/model.go b/pkg/jobparser/model.go index 2ad615d..e5bbbcd 100644 --- a/pkg/jobparser/model.go +++ b/pkg/jobparser/model.go @@ -172,10 +172,20 @@ type RunDefaults struct { WorkingDirectory string `yaml:"working-directory,omitempty"` } +type WorkflowDispatchInput struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + Required bool `yaml:"required"` + Default string `yaml:"default"` + Type string `yaml:"type"` + Options []string `yaml:"options"` +} + type Event struct { Name string acts map[string][]string schedules []map[string]string + inputs []WorkflowDispatchInput } func (evt *Event) IsSchedule() bool { @@ -190,6 +200,47 @@ func (evt *Event) Schedules() []map[string]string { return evt.schedules } +func (evt *Event) Inputs() []WorkflowDispatchInput { + return evt.inputs +} + +func parseWorkflowDispatchInputs(inputs map[string]interface{}) ([]WorkflowDispatchInput, error) { + var results []WorkflowDispatchInput + for name, input := range inputs { + inputMap, ok := input.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("invalid input: %v", input) + } + input := WorkflowDispatchInput{ + Name: name, + } + if desc, ok := inputMap["description"].(string); ok { + input.Description = desc + } + if required, ok := inputMap["required"].(bool); ok { + input.Required = required + } + if defaultVal, ok := inputMap["default"].(string); ok { + input.Default = defaultVal + } + if inputType, ok := inputMap["type"].(string); ok { + input.Type = inputType + } + if options, ok := inputMap["options"].([]string); ok { + input.Options = options + } else if options, ok := inputMap["options"].([]interface{}); ok { + for _, option := range options { + if opt, ok := option.(string); ok { + input.Options = append(input.Options, opt) + } + } + } + + results = append(results, input) + } + return results, nil +} + func ParseRawOn(rawOn *yaml.Node) ([]*Event, error) { switch rawOn.Kind { case yaml.ScalarNode: @@ -228,7 +279,6 @@ func ParseRawOn(rawOn *yaml.Node) ([]*Event, error) { if v == nil { res = append(res, &Event{ Name: k, - acts: map[string][]string{}, }) continue } @@ -236,15 +286,14 @@ func ParseRawOn(rawOn *yaml.Node) ([]*Event, error) { case string: res = append(res, &Event{ Name: k, - acts: map[string][]string{}, }) case []string: res = append(res, &Event{ Name: k, - acts: map[string][]string{}, }) case map[string]interface{}: acts := make(map[string][]string, len(t)) + var inputs []WorkflowDispatchInput for act, branches := range t { switch b := branches.(type) { case string: @@ -259,13 +308,28 @@ func ParseRawOn(rawOn *yaml.Node) ([]*Event, error) { return nil, fmt.Errorf("unknown on type: %#v", branches) } } + case map[string]interface{}: + if k != "workflow_dispatch" && act != "inputs" { + return nil, fmt.Errorf("unknown on type: %#v", branches) + } + inputs, err = parseWorkflowDispatchInputs(b) + if err != nil { + return nil, err + } default: return nil, fmt.Errorf("unknown on type: %#v", branches) } } + if len(inputs) == 0 { + inputs = nil + } + if len(acts) == 0 { + acts = nil + } res = append(res, &Event{ - Name: k, - acts: acts, + Name: k, + acts: acts, + inputs: inputs, }) case []interface{}: if k != "schedule" { @@ -285,6 +349,9 @@ func ParseRawOn(rawOn *yaml.Node) ([]*Event, error) { } } } + if len(schedules) == 0 { + schedules = nil + } res = append(res, &Event{ Name: k, schedules: schedules, diff --git a/pkg/jobparser/model_test.go b/pkg/jobparser/model_test.go index 859ee92..009ef15 100644 --- a/pkg/jobparser/model_test.go +++ b/pkg/jobparser/model_test.go @@ -186,6 +186,60 @@ func TestParseRawOn(t *testing.T) { }, }, }, + { + input: `on: + workflow_dispatch: + inputs: + logLevel: + description: 'Log level' + required: true + default: 'warning' + type: choice + options: + - info + - warning + - debug + tags: + description: 'Test scenario tags' + required: false + type: boolean + environment: + description: 'Environment to run tests against' + type: environment + required: true + push: +`, + result: []*Event{ + { + Name: "workflow_dispatch", + inputs: []WorkflowDispatchInput{ + { + Name: "logLevel", + Description: "Log level", + Required: true, + Default: "warning", + Type: "choice", + Options: []string{"info", "warning", "debug"}, + }, + { + Name: "tags", + Description: "Test scenario tags", + Required: false, + Type: "boolean", + }, + { + Name: "environment", + Description: "Environment to run tests against", + Type: "environment", + Required: true, + }, + }, + }, + { + Name: "push", + }, + }, + }, } for _, kase := range kases { t.Run(kase.input, func(t *testing.T) { @@ -230,8 +284,7 @@ func TestParseMappingNode(t *testing.T) { { input: "on:\n push:\n branches:\n - master", scalars: []string{"push"}, - datas: []interface { - }{ + datas: []interface{}{ map[string]interface{}{ "branches": []interface{}{"master"}, },