Skip to content

Commit

Permalink
Proof of concept of syntax sugar (#47)
Browse files Browse the repository at this point in the history
* Proof of concept of syntax sugar

* Update pkg/larker/larker_test.go

Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com>

* newlines

* commented why we need floats

* Fixed starlark.Int convertion

Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com>
  • Loading branch information
fkorotkov and edigaryev committed Aug 26, 2020
1 parent d0dc02b commit 77828e0
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 25 deletions.
4 changes: 2 additions & 2 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ task:
container:
image: golangci/golangci-lint:latest
name: Lint
script: golangci-lint run -v --out-format json > golangci.json
lint_script: golangci-lint run -v --out-format json > golangci.json
always:
artifacts:
report_artifacts:
path: golangci.json
type: text/json
format: golangci
Expand Down
14 changes: 12 additions & 2 deletions pkg/larker/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func convertList(l *starlark.List) (result []interface{}) {
case *starlark.Dict:
result = append(result, convertDict(value))
default:
result = append(result, value)
result = append(result, convertPrimitive(value))
}
}

Expand All @@ -39,11 +39,21 @@ func convertDict(d *starlark.Dict) yaml.MapSlice {
case *starlark.Dict:
sliceItem = yaml.MapItem{Key: key, Value: convertDict(value)}
default:
sliceItem = yaml.MapItem{Key: key, Value: value}
sliceItem = yaml.MapItem{Key: key, Value: convertPrimitive(value)}
}

slice = append(slice, sliceItem)
}

return slice
}

func convertPrimitive(value starlark.Value) interface{} {
switch typedValue := value.(type) {
case starlark.Int:
res, _ := typedValue.Int64()
return res
default:
return typedValue
}
}
5 changes: 5 additions & 0 deletions pkg/larker/larker.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"github.com/cirruslabs/cirrus-cli/pkg/larker/fs"
"go.starlark.net/resolve"
"go.starlark.net/starlark"
"gopkg.in/yaml.v2"
)
Expand All @@ -26,6 +27,10 @@ func New(opts ...Option) *Larker {
fs: fs.NewDummyFileSystem(),
}

// weird global init by Starlark
// we need floats at least for configuring CPUs for containers
resolve.AllowFloat = true

// Apply options
for _, opt := range opts {
opt(lrk)
Expand Down
34 changes: 14 additions & 20 deletions pkg/larker/larker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,28 @@ package larker_test
import (
"context"
"errors"
"github.com/cirruslabs/cirrus-cli/internal/executor"
"github.com/cirruslabs/cirrus-cli/internal/testutil"
"github.com/cirruslabs/cirrus-cli/pkg/larker"
"github.com/cirruslabs/cirrus-cli/pkg/larker/fs"
"github.com/cirruslabs/cirrus-cli/pkg/parser"
"github.com/stretchr/testify/assert"
"io/ioutil"
"path/filepath"
"testing"
"time"
)

// TestSimpleTask ensures that .cirrus.star is able to generate the simplest possible configuration
// that gets executed without any problems.
// TestSimpleTask ensures that .cirrus.star is able to generate the simplest possible configuration.
func TestSimpleTask(t *testing.T) {
dir := testutil.TempDirPopulatedWith(t, "testdata/simple-task")
validateExpected(t, "testdata/simple-task")
}

// TestSugarCoatedTask ensures that .cirrus.star is able to use imported functions for task generation.
func TestSugarCoatedTask(t *testing.T) {
validateExpected(t, "testdata/sugar-coated-task")
}

func validateExpected(t *testing.T, testDir string) {
dir := testutil.TempDirPopulatedWith(t, testDir)

// Read the source code
source, err := ioutil.ReadFile(filepath.Join(dir, ".cirrus.star"))
Expand All @@ -27,30 +33,18 @@ func TestSimpleTask(t *testing.T) {
}

// Run the source code to produce a YAML configuration
lrk := larker.New()
lrk := larker.New(larker.WithFileSystem(fs.NewLocalFileSystem(dir)))
configuration, err := lrk.Main(context.Background(), string(source))
if err != nil {
t.Fatal(err)
}

// Parse YAML
p := parser.Parser{}
result, err := p.Parse(configuration)
if err != nil {
t.Fatal(err)
}
if len(result.Errors) != 0 {
t.Fatal(result.Errors[0])
}

e, err := executor.New(dir, result.Tasks)
expectedConfiguration, err := ioutil.ReadFile(filepath.Join(dir, "expected.yaml"))
if err != nil {
t.Fatal(err)
}

if err := e.Run(context.Background()); err != nil {
t.Fatal(err)
}
assert.YAMLEq(t, string(expectedConfiguration), configuration)
}

// TestLoadFileSystemLocal ensures that modules can be loaded from the local file system.
Expand Down
2 changes: 1 addition & 1 deletion pkg/larker/testdata/simple-task/.cirrus.star
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def main(ctx):
"image": "debian:latest",
},
"script": [
"true",
"printenv",
],
},
]
5 changes: 5 additions & 0 deletions pkg/larker/testdata/simple-task/expected.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
task:
container:
image: debian:latest
script:
- printenv
18 changes: 18 additions & 0 deletions pkg/larker/testdata/sugar-coated-task/.cirrus.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
load("core.star", "task", "container", "script", "always", "artifacts")

def main(ctx):
return [
task(
name="Lint",
instance=container("golangci/golangci-lint:latest", cpu=1.0, memory=512),
env={
"STARLARK": True
},
instructions=[
script("lint", "echo $STARLARK", "golangci-lint run -v --out-format json > golangci.json"),
always(
artifacts("report", "golangci.json", type="text/json", format="golangci")
)
]
)
]
53 changes: 53 additions & 0 deletions pkg/larker/testdata/sugar-coated-task/core.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
def task(name, instance, env={}, instructions=[]):
result = {
'name': name,
'env': env,
}
result.update(instance.items())
for instruction in instructions:
result.update(instruction.items())
return result


def script(name, *lines):
return {
name + '_script': lines
}


def artifacts(name, path, type="", format=""):
result = {
'path': path,
}
if type != "":
result['type'] = type
if format != "":
result['format'] = format
return {
name + '_artifacts': result
}


def container(image="", dockerfile="", cpu=2.0, memory=4096):
result = dict()
if image != "":
result['image'] = image
if dockerfile != "":
result['dockerfile'] = dockerfile
result['cpu'] = cpu
result['memory'] = memory
return {
'container': result
}


def always(instruction):
return {'always': instruction}


def on_failure(instruction):
return {'on_failure': instruction}


def on_sucess(instruction):
return {'on_sucess': instruction}
16 changes: 16 additions & 0 deletions pkg/larker/testdata/sugar-coated-task/expected.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
task:
name: Lint
env:
STARLARK: true
container:
image: golangci/golangci-lint:latest
cpu: 1
memory: 512
lint_script:
- echo $STARLARK
- golangci-lint run -v --out-format json > golangci.json
always:
report_artifacts:
path: golangci.json
type: text/json
format: golangci

0 comments on commit 77828e0

Please sign in to comment.