blob: 59db1888c8ff76eed7180bae625b78adc0c94f3d [file] [log] [blame] [view]
# 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`