Drone

Drone-convert-starlark and drone-cli uses different versions and script errors are unhelpful

the one in drone-cli go.mod lacks starlark features.

In any case I was trying to use the fail() builtin to add validation inside a complex build and it isnt defined.

Upgrading to latest version in drone cli solved it, I have no idea if the version in the starlark convert plugin is new enough to support it but at least for now I can use fail while developing the starlark drone build.

iff --git a/go.mod b/go.mod
index ffefde4..80178bc 100644
--- a/go.mod
+++ b/go.mod
@@ -34,11 +34,11 @@ require (
        github.com/pkg/errors v0.8.0
        github.com/urfave/cli v1.20.0
        github.com/vinzenz/yaml v0.0.0-20170920082545-91409cdd725d
-       go.starlark.net v0.0.0-20190219202100-4eb76950c5f0
+       go.starlark.net v0.0.0-20200203144150-6677ee5c7211
        golang.org/x/net v0.0.0-20181005035420-146acd28ed58
        golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890
        golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
-       golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e
+       golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c
        google.golang.org/appengine v1.3.0
        gopkg.in/yaml.v2 v2.2.2
 )

the one in the convert plugin is

   go.starlark.net v0.0.0-20190820173200-988906f77f65
▶13 ~/src/.../api git:drone-starlark?*+
:27 tf@whale!$ watchexec -e .star -- 'drone starlark && drone fmt --save && cat .drone.yml'
2020/03/05 13:27:37 .drone.star:90:5: undefined: fail
^C (...upgrading starlark..)
▶13 ~/src/.../api git:drone-starlark?*+
:27 tf@whale!$ watchexec -e .star -- 'drone starlark && drone fmt --save && cat .drone.yml'
2020/03/05 13:27:50 fail: asd

if its worth anything as far as testing goes I have been converting a thousand+ lines yml file to a many hundred lines long starlark script today and I am going to continue tomorrow and so far I have not seen any issues from upgrading the dep in drone-cli.

I will probably continue doing this for a client tomorrow and if it works out well maybe for a few weeks as well

I got into a situation where I had a problem where I needed some context form the error output…

So I made another small chage in drone-cli

diff --git a/drone/starlark/starlark.go b/drone/starlark/starlark.go
index 9ac77a2..b0fa794 100644
--- a/drone/starlark/starlark.go
+++ b/drone/starlark/starlark.go
@@ -154,6 +154,9 @@ func generate(c *cli.Context) error {
        })
        mainVal, err = starlark.Call(thread, main, args, nil)
        if err != nil {
+               if e, ok := err.(*starlark.EvalError); ok {
+                       return fmt.Errorf("starlark eval error:\n%s", e.Backtrace())
+               }
                return err
        }

without changes you get a kind of useless error message:

2020/03/06 10:03:44 update: got NoneType, want iterable

with changes:

2020/03/06 10:04:14 starlark eval error:
Traceback (most recent call last):
  .drone.star:20:21: in main
  .drone.star:115:23: in tag_pipeline
  .drone.star:477:20: in ecs_stage_step
  .drone.star:436:24: in ecs_step
  <builtin>: in update
Error: update: got NoneType, want iterable

since drone calls starlark at multiple stages I have changed it to this now:

diff --git a/drone/starlark/starlark.go b/drone/starlark/starlark.go
index 9ac77a2..cccbba1 100644
--- a/drone/starlark/starlark.go
+++ b/drone/starlark/starlark.go
@@ -99,6 +99,7 @@ var Command = cli.Command{
 }

 func generate(c *cli.Context) error {
+
        source := c.String("source")
        target := c.String("target")

@@ -114,7 +115,7 @@ func generate(c *cli.Context) error {
        }
        globals, err := starlark.ExecFile(thread, source, data, nil)
        if err != nil {
-               return err
+               return prettyStarlarkError(err)
        }

        mainVal, ok := globals["main"]
@@ -154,9 +155,8 @@ func generate(c *cli.Context) error {
        })
        mainVal, err = starlark.Call(thread, main, args, nil)
        if err != nil {
-               return err
+               return prettyStarlarkError(err)
        }
-
        buf := new(bytes.Buffer)
        switch v := mainVal.(type) {
        case *starlark.List:
@@ -304,7 +304,7 @@ func makeLoad() func(thread *starlark.Thread, module string) (starlark.StringDic
                        // Load it.
                        thread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
                        globals, err := starlark.ExecFile(thread, module, nil, nil)
-                       e = &entry{globals, err}
+                       e = &entry{globals, prettyStarlarkError(err)}

                        // Update the cache.
                        cache[module] = e
@@ -312,3 +312,12 @@ func makeLoad() func(thread *starlark.Thread, module string) (starlark.StringDic
                return e.globals, e.err
        }
 }
+
+// prettyStarlarkError returns a suitable human readable error for a
+// starlark.Exec error or returns the error unmodified.
+func prettyStarlarkError(err error) error {
+       if err, ok := err.(*starlark.EvalError); ok {
+               return fmt.Errorf("starlark eval error:\n%s", err.Backtrace())
+       }
+       return err
+}

I made 2 pull requests for this, added backtraces to the error messages of both projects and upped the starlark version to the same latest version that has the fail builtin for sure.