Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cdf1e5788 | ||
|
|
ab381649da |
@@ -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:
|
||||
@@ -218,79 +269,119 @@ func ParseRawOn(rawOn *yaml.Node) ([]*Event, error) {
|
||||
}
|
||||
return res, nil
|
||||
case yaml.MappingNode:
|
||||
events, triggers, err := parseMappingNode[interface{}](rawOn)
|
||||
events, triggers, err := parseMappingNode[yaml.Node](rawOn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := make([]*Event, 0, len(events))
|
||||
for i, k := range events {
|
||||
v := triggers[i]
|
||||
if v == nil {
|
||||
switch v.Kind {
|
||||
case yaml.ScalarNode:
|
||||
res = append(res, &Event{
|
||||
Name: k,
|
||||
acts: map[string][]string{},
|
||||
})
|
||||
continue
|
||||
}
|
||||
switch t := v.(type) {
|
||||
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))
|
||||
for act, branches := range t {
|
||||
switch b := branches.(type) {
|
||||
case string:
|
||||
acts[act] = []string{b}
|
||||
case []string:
|
||||
acts[act] = b
|
||||
case []interface{}:
|
||||
acts[act] = make([]string, len(b))
|
||||
for i, v := range b {
|
||||
var ok bool
|
||||
if acts[act][i], ok = v.(string); !ok {
|
||||
return nil, fmt.Errorf("unknown on type: %#v", branches)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown on type: %#v", branches)
|
||||
}
|
||||
}
|
||||
res = append(res, &Event{
|
||||
Name: k,
|
||||
acts: acts,
|
||||
})
|
||||
case []interface{}:
|
||||
if k != "schedule" {
|
||||
return nil, fmt.Errorf("unknown on type: %#v", v)
|
||||
case yaml.SequenceNode:
|
||||
var t []interface{}
|
||||
err := v.Decode(&t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
schedules := make([]map[string]string, len(t))
|
||||
for i, tt := range t {
|
||||
vv, ok := tt.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown on type: %#v", v)
|
||||
}
|
||||
schedules[i] = make(map[string]string, len(vv))
|
||||
for k, vvv := range vv {
|
||||
var ok bool
|
||||
if schedules[i][k], ok = vvv.(string); !ok {
|
||||
return nil, fmt.Errorf("unknown on type: %#v", v)
|
||||
if k == "schedule" {
|
||||
for i, tt := range t {
|
||||
vv, ok := tt.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown on type(schedule): %#v", v)
|
||||
}
|
||||
schedules[i] = make(map[string]string, len(vv))
|
||||
for k, vvv := range vv {
|
||||
var ok bool
|
||||
if schedules[i][k], ok = vvv.(string); !ok {
|
||||
return nil, fmt.Errorf("unknown on type(schedule): %#v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(schedules) == 0 {
|
||||
schedules = nil
|
||||
}
|
||||
res = append(res, &Event{
|
||||
Name: k,
|
||||
schedules: schedules,
|
||||
})
|
||||
case yaml.MappingNode:
|
||||
acts := make(map[string][]string, len(v.Content)/2)
|
||||
var inputs []WorkflowDispatchInput
|
||||
expectedKey := true
|
||||
var act string
|
||||
for _, content := range v.Content {
|
||||
if expectedKey {
|
||||
if content.Kind != yaml.ScalarNode {
|
||||
return nil, fmt.Errorf("key type not string: %#v", content)
|
||||
}
|
||||
act = ""
|
||||
err := content.Decode(&act)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
switch content.Kind {
|
||||
case yaml.SequenceNode:
|
||||
var t []string
|
||||
err := content.Decode(&t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acts[act] = t
|
||||
case yaml.MappingNode:
|
||||
if k != "workflow_dispatch" || act != "inputs" {
|
||||
return nil, fmt.Errorf("map should only for workflow_dispatch but %s: %#v", act, content)
|
||||
}
|
||||
|
||||
var key string
|
||||
for i, vv := range content.Content {
|
||||
if i%2 == 0 {
|
||||
if vv.Kind != yaml.ScalarNode {
|
||||
return nil, fmt.Errorf("key type not string: %#v", vv)
|
||||
}
|
||||
key = ""
|
||||
if err := vv.Decode(&key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if vv.Kind != yaml.MappingNode {
|
||||
return nil, fmt.Errorf("key type not map(%s): %#v", key, vv)
|
||||
}
|
||||
|
||||
input := WorkflowDispatchInput{}
|
||||
if err := vv.Decode(&input); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
input.Name = key
|
||||
inputs = append(inputs, input)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown on type: %#v", content)
|
||||
}
|
||||
}
|
||||
expectedKey = !expectedKey
|
||||
}
|
||||
if len(inputs) == 0 {
|
||||
inputs = nil
|
||||
}
|
||||
if len(acts) == 0 {
|
||||
acts = nil
|
||||
}
|
||||
res = append(res, &Event{
|
||||
Name: k,
|
||||
acts: acts,
|
||||
inputs: inputs,
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown on type: %#v", v)
|
||||
return nil, fmt.Errorf("unknown on type: %v", v.Kind)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
|
||||
@@ -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"},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user