Writing multi-line strings from input objects to file in Bash scripts

In native processes ( using exec: ), one can write multi-line strings to a file taking advantage of the task.workDir variable.

    exec:
    def nested_object = [ letters: [ 'A', 'B', 'C' ], meta: [ id: 123, str: 'text' ] ]
    def yamlBuilder = new groovy.yaml.YamlBuilder()
    yamlBuilder(nested_object)
    file("${task.workDir}/data.yml").text = yamlBuilder.toString()

However task.workDir is not available in script: processes. We can however redirect strings into a file using heredocs, or other methods. Writing formatted multi-line strings becomes a problem in bash scripts as this can alter indentation causing a script to not work.

    script:
    def nested_object = [ letters: [ 'A', 'B', 'C' ], meta: [ id: 123, str: 'text' ] ]
    def yamlBuilder = new groovy.yaml.YamlBuilder()
    yamlBuilder(nested_object)
    """
    cat <<-END_YAML > data.yml
    ${yamlBuilder.toString()}
    END_YAML
    """

results in a bash script that looks like:

#!/bin/bash -ue
cat <<-END_YAML > data.yml
    ---
letters:
- "A"
- "B"
- "C"
meta:
  id: 123
  str: "text"

    END_YAML

and a data.yml that looks like:

    ---
letters:
- "A"
- "B"
- "C"
meta:
  id: 123
  str: "text"

    END_YAML

In order to keep the correct indentation, one can use the tokenize() and join() methods on the multi-line string to correct formatting.

    script:
    def nested_object = [ letters: [ 'A', 'B', 'C' ], meta: [ id: 123, str: 'text' ] ]
    def yamlBuilder = new groovy.yaml.YamlBuilder()
    yamlBuilder(nested_object)
    """
    cat <<-END_YAML > data.yml
    ${yamlBuilder.toString().tokenize('\n').join('\n    ')}
    END_YAML
    """

where tokenize('\n') turns the multi-line string into a list of strings, and
join('\n ') concatenates the list with new-lines followed by the indentation of the script ( 4 spaces in this case ). This allows indentation to be correctly stripped from the multi-line script that will become the bash script.

#!/bin/bash -ue
cat <<-END_YAML > data.yml
---
letters:
- "A"
- "B"
- "C"
meta:
  id: 123
  str: "text"
END_YAML

writing a correct data.yml file:

---
letters:
- "A"
- "B"
- "C"
meta:
  id: 123
  str: "text"