| # Jsonnet Rules |
| |
| <div class="toc"> |
| <h2>Rules</h2> |
| <ul> |
| <li><a href="#jsonnet_library">jsonnet_library</a></li> |
| <li><a href="#jsonnet_to_json">jsonnet_to_json</a></li> |
| <li><a href="#jsonnet_to_json_test">jsonnet_to_json_test</a></li> |
| </ul> |
| </div> |
| |
| ## Overview |
| |
| These are build rules for working with [Jsonnet][jsonnet] files with Bazel. |
| |
| [jsonnet]: http://google.github.io/jsonnet/doc/ |
| |
| ## Setup |
| |
| To use the Jsonnet rules, add the following to your `WORKSPACE` file to add the |
| external repositories for Jsonnet: |
| |
| ```python |
| load("@bazel_tools//tools/build_defs/jsonnet:jsonnet.bzl", "jsonnet_repositories") |
| |
| jsonnet_repositories() |
| ``` |
| |
| <a name="#jsonnet_library"></a> |
| ## jsonnet_library |
| |
| ```python |
| jsonnet_library(name, srcs, deps, imports) |
| ``` |
| |
| <table class="table table-condensed table-bordered table-params"> |
| <colgroup> |
| <col class="col-param" /> |
| <col class="param-description" /> |
| </colgroup> |
| <thead> |
| <tr> |
| <th colspan="2">Attributes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td><code>name</code></td> |
| <td> |
| <code>Name, required</code> |
| <p>A unique name for this rule.</p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>srcs</code></td> |
| <td> |
| <code>List of Labels, required</code> |
| <p> |
| List of <code>.jsonnet</code> files that comprises this Jsonnet |
| library. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>deps</code></td> |
| <td> |
| <code>List of labels, optional</code> |
| <p> |
| List of targets that are required by the <code>srcs</code> Jsonnet |
| files. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>imports</code></td> |
| <td> |
| <code>List of strings, optional</code> |
| <p> |
| List of import <code>-J</code> flags to be passed to the |
| <code>jsonnet</code> compiler. |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| ### Example |
| |
| Suppose you have the following directory structure: |
| |
| ``` |
| [workspace]/ |
| WORKSPACE |
| configs/ |
| BUILD |
| backend.jsonnet |
| frontend.jsonnet |
| ``` |
| |
| You can use the `jsonnet_library` rule to build a collection of `.jsonnet` |
| files that can be imported by other `.jsonnet` files as dependencies: |
| |
| `configs/BUILD`: |
| |
| ```python |
| load("@bazel_tools//tools/build_defs/jsonnet:jsonnet.bzl", "jsonnet_library") |
| |
| jsonnet_library( |
| name = "configs", |
| srcs = [ |
| "backend.jsonnet", |
| "frontend.jsonnet", |
| ], |
| ) |
| ``` |
| |
| <a name="#jsonnet_to_json"></a> |
| ## jsonnet\_to\_json |
| |
| ```python |
| jsonnet_to_json(name, src, deps, outs, multiple_outputs, imports, vars, code_vars) |
| ``` |
| |
| <table class="table table-condensed table-bordered table-params"> |
| <colgroup> |
| <col class="col-param" /> |
| <col class="param-description" /> |
| </colgroup> |
| <thead> |
| <tr> |
| <th colspan="2">Attributes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td><code>name</code></td> |
| <td> |
| <code>Name, required</code> |
| <p>A unique name for this rule.</p> |
| <p> |
| This name will be used as the name of the JSON file generated by this |
| rule. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>src</code></td> |
| <td> |
| <code>Label, required</code> |
| <p> |
| The <code>.jsonnet</code> file to convert to JSON. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>deps</code></td> |
| <td> |
| <code>List of labels, optional</code> |
| <p> |
| List of targets that are required by the <code>src</code> Jsonnet |
| file. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>outs</code></td> |
| <td> |
| <code>List of Filenames, optional</code> |
| <p> |
| Names of the output .json files to be generated by this rule. |
| </p> |
| <p> |
| If you are generating only a single JSON file and are not using |
| jsonnet multiple output files, then this attribute should only |
| contain the file name of the JSON file you are generating. |
| </p> |
| <p> |
| If you are generating multiple JSON files using jsonnet multiple file |
| output (<code>jsonnet -m</code>), then list the file names of all the |
| JSON files to be generated. The file names specified here must match |
| the file names specified in your <code>src</code> Jsonnet file. |
| </p> |
| <p> |
| For the case where multiple file output is used but only for |
| generating one output file, set the <code>multiple_outputs</code> |
| attribute to 1 to explicitly enable the <code>-m</code> flag for |
| multiple file output. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>multiple_outputs</code></td> |
| <td> |
| <code>bool, optional, default 0</code> |
| <p> |
| Set to 1 to explicitly enable multiple file output via the |
| <code>jsonnet -m</code> flag. |
| </p> |
| <p> |
| This is used for the case where multiple file output is used but only |
| for generating a single output file. For example: |
| </p> |
| <pre> |
| local foo = import "foo.jsonnet"; |
| |
| { |
| "foo.json": foo, |
| } |
| </pre> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>imports</code></td> |
| <td> |
| <code>List of strings, optional</code> |
| <p> |
| List of import <code>-J</code> flags to be passed to the |
| <code>jsonnet</code> compiler. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>vars</code></td> |
| <td> |
| <code>String dict, optional</code> |
| <p> |
| Map of variables to pass to jsonnet via <code>--var key=value</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>code_vars</code></td> |
| <td> |
| <code>String dict, optional</code> |
| <p> |
| Map of code variables to pass to jsonnet via |
| <code>--code-var key=value</code>. |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| ### Example |
| |
| Suppose you have the following directory structure: |
| |
| ``` |
| [workspace]/ |
| WORKSPACE |
| workflows/ |
| BUILD |
| workflow.jsonnet |
| wordcount.jsonnet |
| intersection.jsonnet |
| ``` |
| |
| Say that `workflow.jsonnet` is a base configuration library for a workflow |
| scheduling system and `wordcount.jsonnet` and `intersection.jsonnet` both |
| import `workflow.jsonnet` to define workflows for performing a wordcount and |
| intersection of two files, respectively. |
| |
| First, create a `jsonnet_library` target with `workflow.jsonnet`: |
| |
| `workflows/BUILD`: |
| |
| ```python |
| load("@bazel_tools//tools/build_defs/jsonnet:jsonnet.bzl", "jsonnet_library") |
| |
| jsonnet_library( |
| name = "workflow", |
| srcs = ["workflow.jsonnet"], |
| ) |
| ``` |
| |
| To compile `wordcount.jsonnet` and `intersection.jsonnet` to JSON, define two |
| `jsonnet_to_json` targets: |
| |
| ```python |
| jsonnet_to_json( |
| name = "wordcount", |
| src = "wordcount.jsonnet", |
| outs = ["wordcount.json"], |
| deps = [":workflow"], |
| ) |
| |
| jsonnet_to_json( |
| name = "intersection", |
| src = "intersection.jsonnet", |
| outs = ["intersection.json"], |
| deps = [":workflow"], |
| ) |
| ``` |
| |
| ### Example: Multiple output files |
| |
| To use Jsonnet's [multiple output files][multiple-output-files], suppose you |
| add a file `shell-workflows.jsonnet` that imports `wordcount.jsonnet` and |
| `intersection.jsonnet`: |
| |
| `workflows/shell-workflows.jsonnet`: |
| |
| ``` |
| local wordcount = import "workflows/wordcount.jsonnet"; |
| local intersection = import "workflows/intersection.jsonnet"; |
| |
| { |
| "wordcount-workflow.json": wordcount, |
| "intersection-workflow.json": intersection, |
| } |
| ``` |
| |
| To compile `shell-workflows.jsonnet` into the two JSON files, |
| `wordcount-workflow.json` and `intersection-workflow.json`, first create a |
| `jsonnet_library` target containing the two files that |
| `shell-workflows.jsonnet` depends on: |
| |
| ```python |
| jsonnet_library( |
| name = "shell-workflows-lib", |
| srcs = [ |
| "wordcount.jsonnet", |
| "intersection.jsonnet", |
| ], |
| deps = [":workflow"], |
| ) |
| ``` |
| |
| Then, create a `jsonnet_to_json` target and set `outs` to the list of output |
| files to indicate that multiple output JSON files are generated: |
| |
| ```python |
| jsonnet_to_json( |
| name = "shell-workflows", |
| src = "shell-workflows.jsonnet", |
| deps = [":shell-workflows-lib"], |
| outs = [ |
| "wordcount-workflow.jsonnet", |
| "intersection-workflow.jsonnet", |
| ], |
| ) |
| ``` |
| |
| [multiple-output-files]: http://google.github.io/jsonnet/doc/commandline.html |
| |
| <a name="#jsonnet_to_json_test"></a> |
| ## jsonnet\_to\_json\_test |
| |
| ```python |
| jsonnet_to_json_test(name, src, deps, imports, golden, error=0, regex=False) |
| ``` |
| |
| <table class="table table-condensed table-bordered table-params"> |
| <colgroup> |
| <col class="col-param" /> |
| <col class="param-description" /> |
| </colgroup> |
| <thead> |
| <tr> |
| <th colspan="2">Attributes</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td><code>name</code></td> |
| <td> |
| <code>Name, required</code> |
| <p>A unique name for this rule.</p> |
| <p> |
| This name will be used as the name of the JSON file generated by this |
| rule. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>src</code></td> |
| <td> |
| <code>Label, required</code> |
| <p> |
| The <code>.jsonnet</code> file to convert to JSON. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>deps</code></td> |
| <td> |
| <code>List of labels, optional</code> |
| <p> |
| List of targets that are required by the <code>src</code> Jsonnet |
| file. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>imports</code></td> |
| <td> |
| <code>List of strings, optional</code> |
| <p> |
| List of import <code>-J</code> flags to be passed to the |
| <code>jsonnet</code> compiler. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>vars</code></td> |
| <td> |
| <code>String dict, optional</code> |
| <p> |
| Map of variables to pass to jsonnet via <code>--var key=value</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>code_vars</code></td> |
| <td> |
| <code>String dict, optional</code> |
| <p> |
| Map of code variables to pass to jsonnet via |
| <code>--code-var key=value</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>golden</code></td> |
| <td> |
| <code>Label, optional</code> |
| <p> |
| The expected (combined stdout and stderr) output to compare to the |
| output of running <code>jsonnet</code> on <code>src</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>error</code></td> |
| <td> |
| <code>Integer, optional, default is 0</code> |
| <p> |
| The expected error code from running <code>jsonnet</code> on |
| <code>src</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><code>regex</code></td> |
| <td> |
| <code>bool, optional, default is False</code> |
| <p> |
| Set to 1 if <code>golden</code> contains a regex used to match |
| the output of running <code>jsonnet</code> on <code>src</code>. |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| ### Example |
| |
| Suppose you have the following directory structure: |
| |
| ``` |
| [workspace]/ |
| WORKSPACE |
| config/ |
| BUILD |
| base_config.jsonnet |
| test_config.jsonnet |
| test_config.json |
| ``` |
| |
| Suppose that `base_config.jsonnet` is a library Jsonnet file, containing the |
| base configuration for a service. Suppose that `test_config.jsonnet` is a test |
| configuration file that is used to test `base_config.jsonnet`, and |
| `test_config.json` is the expected JSON output from compiling |
| `test_config.jsonnet`. |
| |
| The `jsonnet_to_json_test` rule can be used to verify that compiling a Jsonnet |
| file produces the expected JSON output. Simply define a `jsonnet_to_json_test` |
| target and provide the input test Jsonnet file and the `golden` file containing |
| the expected JSON output: |
| |
| `config/BUILD`: |
| |
| ```python |
| load( |
| "@bazel_tools//tools/build_defs/jsonnet:jsonnet.bzl", |
| "jsonnet_library", |
| "jsonnet_to_json_test", |
| ) |
| |
| jsonnet_library( |
| name = "base_config", |
| srcs = ["base_config.jsonnet"], |
| ) |
| |
| jsonnet_to_json_test( |
| name = "test_config_test", |
| src = "test_config", |
| deps = [":base_config"], |
| golden = "test_config.json", |
| ) |
| ``` |
| |
| To run the test: `bazel test //config:test_config_test` |
| |
| ### Example: Negative tests |
| |
| Suppose you have the following directory structure: |
| |
| ``` |
| [workspace]/ |
| WORKSPACE |
| config/ |
| BUILD |
| base_config.jsonnet |
| invalid_config.jsonnet |
| invalid_config.output |
| ``` |
| |
| Suppose that `invalid_config.jsonnet` is a Jsonnet file used to verify that |
| an invalid config triggers an assertion in `base_config.jsonnet`, and |
| `invalid_config.output` is the expected error output. |
| |
| The `jsonnet_to_json_test` rule can be used to verify that compiling a Jsonnet |
| file results in an expected error code and error output. Simply define a |
| `jsonnet_to_json_test` target and provide the input test Jsonnet file, the |
| expected error code in the `error` attribute, and the `golden` file containing |
| the expected error output: |
| |
| `config/BUILD`: |
| |
| ```python |
| load( |
| "@bazel_tools//tools/build_defs/jsonnet:jsonnet.bzl", |
| "jsonnet_library", |
| "jsonnet_to_json_test", |
| ) |
| |
| jsonnet_library( |
| name = "base_config", |
| srcs = ["base_config.jsonnet"], |
| ) |
| |
| jsonnet_to_json_test( |
| name = "invalid_config_test", |
| src = "invalid_config", |
| deps = [":base_config"], |
| golden = "invalid_config.output", |
| error = 1, |
| ) |
| ``` |
| |
| To run the test: `bazel test //config:invalid_config_test` |