DEV Community

Alexey Melezhik
Alexey Melezhik

Posted on

SparrowCI - DSL is dead, long live DSL!

TL;DR - How to write YAML DSL pipelines without frustration.


To be honest, I am not in favor of modern DSL based tools.

At least, I am not in favor of them when people try to use those tools for the things they are not very well designed for ( which starts to happen pretty quickly ).

Starting from Ansible the course of declarative style DSL languages seems has taken the market, while it does not always mean those tools are easy to use and maintain.


Well, for simple, typical cases ala make && sudo make install this approach works really well, while for more complex scenarios where a pipeline logic implies some data flow and sharing states between steps the idea of confining everything into a declarative (none imperative) approach results in ugly and hard to maintain code.

Consider this simple example of GH actions pipeline of setting 2 variables in 2 steps and using them in downstream code:

steps:
  - id: task1
    run: echo "::set-output name=test::hello"

  - id: task2
    run: echo "::set-output name=test::world"

  - name: main 
    run: |
      echo "Task1 returns: ${{ steps.task1.outputs.test }}"
      echo "Task2 returns: ${{ steps.task2_outputs.test }}"
Enter fullscreen mode Exit fullscreen mode

IMHO here we have a code that is hard to read (we use none relevant print statements to set a step output), and thus to maintain.

These typical question would pop up:

  • If I use high level general purpose programming languages why should I use print statements to declare return output ?
  • How could a step return structured, complex object data?

  • And the last but not the least - how to pass arbitrary configuration as a task input?


This is why ( well partly because of that ) I've created SparrowCI - super fun and flexible CI system with many programming languages support


SparrowCI DSL still allows one to write pipeline code as YAML based steps, however, every step essentially is a function written in a language of choice and thus accepting some input parameters and returning some output values.

That is it.

In SparrowCI have a good balance of YAML based pipelines for people not willing to go imperative path and do any serious coding and flexibility and freedom to express elementary units of pipeline logic as functions written on regular programming languages:

  tasks:
    -
      language: Python
      name: task1
      code: |
        print("task1 start")
        print(f"you passed {config()['message']}")
        update_state({"test": "hello"})
    -
      name: task2
      language: Python
      code: |
        print("task2 start")
        print(f"you passed {config()['message']}")
        update_state({"test": "world"})
    -
      name: main
      language: Python
      default: true
      depends: 
        - 
          name: task1
          config:
            message: hello task1
        - 
          name: task2
          config:
            message: hello task2
      code: |
        print(f"Task1 returns: {config()["tasks"]["task1"]["state"]["test"]}")
        print(f"Task2 returns: {config()["tasks"]["task2"]["state"]["test"]}")

Enter fullscreen mode Exit fullscreen mode

So, with that being said - DSL(YAML) is dead, long live DSL(YAML)!

Top comments (0)