diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e69de29b..d920ce44 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -0,0 +1,27 @@ +## Commit Checklist + +Thank you for creating a pull request! To help us review / merge this can you make sure that your PR adheres as much as possible to the following. + +### The Basics + +- Commit is a single logical unit of work, only use multiple commits if doing different tasks +- Commit does not include commented out code or unneeded files +- rebase of main branch + +### The Content + +- Must include testing for bug or feature +- Must include appropriate documentation changes if it is introducing a new feature or changing existing functionality +- Must pass existing test suites + +### The Commit Message + +- Short meaningful description (ex: remove deprecated steps) +- Uses the imperative, present tense: "change", not "changed" or "changes" +- Includes motivation for the change, and contrasts its implementation with the previous behavior + +### The Pull Request + +- What is the reason for this change +- Example usage of the failure for a bug, or configuration and expected output for a feature +- Steps to test the change diff --git a/plugin/converter/starlark/args.go b/plugin/converter/starlark/args.go index d9ebc61f..edc8bf2b 100644 --- a/plugin/converter/starlark/args.go +++ b/plugin/converter/starlark/args.go @@ -15,6 +15,9 @@ package starlark import ( + "fmt" + "reflect" + "github.com/drone/drone/core" "go.starlark.net/starlark" @@ -38,27 +41,82 @@ import ( // TODO(bradrydzewski) add build parent // TODO(bradrydzewski) add build timestamp -func createArgs(repo *core.Repository, build *core.Build, input map[string]interface{}) []starlark.Value { - return []starlark.Value{ +func createArgs(repo *core.Repository, build *core.Build, input map[string]interface{}) ([]starlark.Value, error) { + inputArgs, err := fromInput(input) + if err != nil { + return nil, err + } + args := []starlark.Value{ starlarkstruct.FromStringDict( starlark.String("context"), starlark.StringDict{ "repo": starlarkstruct.FromStringDict(starlark.String("repo"), fromRepo(repo)), "build": starlarkstruct.FromStringDict(starlark.String("build"), fromBuild(build)), - "input": starlarkstruct.FromStringDict(starlark.String("input"), fromInput(input)), + "input": starlarkstruct.FromStringDict(starlark.String("input"), inputArgs), }, ), } + return args, nil } -func fromInput(input map[string]interface{}) starlark.StringDict { +func fromInput(input map[string]interface{}) (starlark.StringDict, error) { out := map[string]starlark.Value{} - for k, v := range input { - if s, ok := v.(string); ok { - out[k] = starlark.String(s) + for key, value := range input { + v := reflect.ValueOf(value) + result, err := toValue(v) + if err != nil { + return nil, err } + out[key] = result } - return out + return out, nil +} + +func toValue(val reflect.Value) (starlark.Value, error) { + kind := val.Kind() + if kind == reflect.Ptr { + kind = val.Elem().Kind() + } + switch kind { + case reflect.Bool: + return starlark.Bool(val.Bool()), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return starlark.MakeInt64(val.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return starlark.MakeUint64(val.Uint()), nil + case reflect.Float32, reflect.Float64: + return starlark.Float(val.Float()), nil + case reflect.Map: + dict := new(starlark.Dict) + for _, key := range val.MapKeys() { + value := val.MapIndex(key) + getValue, err := toValue(reflect.ValueOf(value.Interface())) + if err != nil { + return nil, err + } + dict.SetKey( + starlark.String(fmt.Sprint(key)), + getValue, + ) + } + return dict, nil + case reflect.String: + return starlark.String(val.String()), nil + case reflect.Slice, reflect.Array: + list := new(starlark.List) + for i := 0; i < val.Len(); i++ { + keyValue := val.Index(i).Interface() + vOf := reflect.ValueOf(keyValue) + result, err := toValue(vOf) + if err != nil { + return nil, err + } + list.Append(result) + } + return list, nil + } + + return nil, fmt.Errorf("type %T is not a supported starlark type", val.Interface()) } func fromBuild(v *core.Build) starlark.StringDict { diff --git a/plugin/converter/starlark/starlark.go b/plugin/converter/starlark/starlark.go index 2ed13ed7..b15a99d2 100644 --- a/plugin/converter/starlark/starlark.go +++ b/plugin/converter/starlark/starlark.go @@ -94,7 +94,10 @@ func Parse(req *core.ConvertArgs, template *core.Template, templateData map[stri // create the input args and invoke the main method // using the input args. - args := createArgs(req.Repo, req.Build, templateData) + args, err := createArgs(req.Repo, req.Build, templateData) + if err != nil { + return "", err + } // set the maximum number of operations in the script. this // mitigates long running scripts. diff --git a/plugin/converter/template.go b/plugin/converter/template.go index 3f151310..b944f9fe 100644 --- a/plugin/converter/template.go +++ b/plugin/converter/template.go @@ -70,6 +70,7 @@ func (p *templatePlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*c if err != nil { return nil, err } + // Check if file is of type Starlark if strings.HasSuffix(templateArgs.Load, ".script") || strings.HasSuffix(templateArgs.Load, ".star") || diff --git a/plugin/converter/template_test.go b/plugin/converter/template_test.go index 1b742166..bf572065 100644 --- a/plugin/converter/template_test.go +++ b/plugin/converter/template_test.go @@ -237,3 +237,65 @@ func TestTemplatePluginConvertJsonnet(t *testing.T) { t.Errorf("Want %q got %q", want, got) } } + +func TestTemplateNestedValuesPluginConvertStarlark(t *testing.T) { + templateArgs, err := ioutil.ReadFile("testdata/starlark-nested.template.yml") + if err != nil { + t.Error(err) + return + } + + req := &core.ConvertArgs{ + Build: &core.Build{ + After: "3d21ec53a331a6f037a91c368710b99387d012c1", + }, + Repo: &core.Repository{ + Slug: "octocat/hello-world", + Config: ".drone.yml", + Namespace: "octocat", + }, + Config: &core.Config{ + Data: string(templateArgs), + }, + } + + beforeInput, err := ioutil.ReadFile("testdata/starlark.input-nested.star") + if err != nil { + t.Error(err) + return + } + + after, err := ioutil.ReadFile("testdata/starlark.input-nested.star.golden") + if err != nil { + t.Error(err) + return + } + + template := &core.Template{ + Name: "test.nested.starlark", + Data: string(beforeInput), + Namespace: "octocat", + } + + controller := gomock.NewController(t) + defer controller.Finish() + + templates := mock.NewMockTemplateStore(controller) + templates.EXPECT().FindName(gomock.Any(), template.Name, req.Repo.Namespace).Return(template, nil) + + plugin := Template(templates) + config, err := plugin.Convert(noContext, req) + if err != nil { + t.Error(err) + return + } + + if config == nil { + t.Error("Want non-nil configuration") + return + } + + if want, got := config.Data, string(after); want != got { + t.Errorf("Want %q got %q", want, got) + } +} diff --git a/plugin/converter/testdata/starlark-nested.template.yml b/plugin/converter/testdata/starlark-nested.template.yml new file mode 100644 index 00000000..401ebab9 --- /dev/null +++ b/plugin/converter/testdata/starlark-nested.template.yml @@ -0,0 +1,8 @@ +kind: template +load: test.nested.starlark +data: + builds: + name: build + image: mcr.microsoft.com/dotnet/sdk:5.0 + commands: + - dotnet build \ No newline at end of file diff --git a/plugin/converter/testdata/starlark.input-nested.star b/plugin/converter/testdata/starlark.input-nested.star new file mode 100644 index 00000000..b29fe69d --- /dev/null +++ b/plugin/converter/testdata/starlark.input-nested.star @@ -0,0 +1,8 @@ +def main(ctx): + return { + "kind": "pipeline", + "name": "default", + "steps": [ + ctx.input.builds + ] + } \ No newline at end of file diff --git a/plugin/converter/testdata/starlark.input-nested.star.golden b/plugin/converter/testdata/starlark.input-nested.star.golden new file mode 100644 index 00000000..2e8eeeaa --- /dev/null +++ b/plugin/converter/testdata/starlark.input-nested.star.golden @@ -0,0 +1 @@ +{"kind": "pipeline", "name": "default", "steps": [{"name": "build", "image": "mcr.microsoft.com/dotnet/sdk:5.0", "commands": ["dotnet build"]}]} \ No newline at end of file diff --git a/scheduler/queue/redis.go b/scheduler/queue/redis.go index f7507a64..f5096a87 100644 --- a/scheduler/queue/redis.go +++ b/scheduler/queue/redis.go @@ -64,13 +64,11 @@ func (c *redisCanceller) Cancelled(ctx context.Context, id int64) (isCancelled b result, err := c.rdb.Get(ctx, redisCancelValuePrefix+ids).Result() if err != nil && err != redis.Nil { - fmt.Println("GOT AN ERROR", err.Error()) ////////////////////////////////////////////////////// return } isCancelled = err != redis.Nil && result == redisCancelValue if isCancelled { - fmt.Println("BUILD IS CANCELED", result) //////////////////////////////////////////////// return } @@ -109,11 +107,8 @@ func (c *redisCanceller) Cancelled(ctx context.Context, id int64) (isCancelled b } if id == idMessage { - fmt.Println("BUILD HAS JUST BEEN CANCELED", m.Payload) //////////////////////////////////////////////// chResult <- true - } else { ////////////////////// - fmt.Println("SOMETHING ELSE IS CANCELLED", m.Payload) //////////////////////////////////////////////// - } ///////////////////////////// + } case <-ctx.Done(): return