Skip to content

Commit 5c9ea31

Browse files
authored
generate docs from zarf schema json (zarf-dev#614)
1 parent f60db07 commit 5c9ea31

18 files changed

+1543
-94
lines changed
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: zarf-schema-check
2+
on:
3+
pull_request:
4+
paths:
5+
- "src/types/**"
6+
- "zarf.schema.json"
7+
8+
jobs:
9+
validate:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: "Install GoLang"
13+
uses: actions/setup-go@v3
14+
with:
15+
go-version: 1.18.x
16+
17+
- name: "Checkout Repo"
18+
uses: actions/checkout@v3
19+
20+
- name: "Setup caching"
21+
uses: actions/cache@v3
22+
with:
23+
path: |
24+
~/.cache/go-build
25+
~/go/pkg/mod
26+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
27+
restore-keys: |
28+
${{ runner.os }}-go-
29+
30+
- name: "Backup Repo Schema Version"
31+
run: 'cp zarf.schema.json zarf.schema.json.bak'
32+
33+
- name: "Regenerate Schema"
34+
run: 'go run main.go tools config-schema > zarf.schema.json'
35+
36+
- name: "Compare Schemas"
37+
run: 'cmp -s zarf.schema.json zarf.schema.json.bak'

.hooks/jsfh-config.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"custom_template_path": ".hooks/zarf-jsfh-template/base.md",
3+
"template_md_options": { "badge_as_image": true, "show_heading_numbers": false },
4+
"show_toc": false,
5+
"show_breadcrumbs": false
6+
}

.hooks/verify-zarf-schema.sh

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
#!/usr/bin/env sh
22
go run main.go tools config-schema > zarf.schema.json
3+
docker run -it -v $(pwd):/app -w /app --rm python:3.8-alpine /bin/sh -c "pip install json-schema-for-humans && generate-schema-doc --config-file .hooks/jsfh-config.json zarf.schema.json docs/4-user-guide/3-zarf-schema.md"

.hooks/zarf-jsfh-template/base.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{% set depth = 0 %}
2+
{{ schema.keywords.get("title").literal | default("Zarf Package Schema") | md_heading(depth) }}
3+
{% set contentBase %}
4+
{% with schema=schema, skip_headers=False, depth=depth %}
5+
{% include "content.md" %}
6+
{% endwith %}
7+
{% endset %}
8+
9+
{{ md_get_toc() }}
10+
11+
{{ contentBase }}
12+
13+
----------------------------------------------------------------------------------------------------------------------------
14+
{% if config.with_footer -%}
15+
Generated from [zarf.schema.json](https://github.com/defenseunicorns/zarf/blob/master/zarf.schema.json){% if config.footer_show_time %} on {{ get_local_time() }}{% endif %}
16+
{%- endif -%}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% filter md_escape_for_table %}
2+
{%- if config.show_breadcrumbs %}
3+
{%- for node in schema.nodes_from_root -%}
4+
{{ node.name_for_breadcrumbs }}{%- if not loop.last %} > {% endif -%}
5+
{%- endfor -%}
6+
{%- else -%}
7+
{{- schema.name_for_breadcrumbs or schema.property_name -}}
8+
{% endif %}
9+
{% endfilter %}

.hooks/zarf-jsfh-template/content.md

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
{#
2+
content is a template and not a macro in md
3+
because macro parameters are not through context
4+
when rendering a template from the macro and it caused
5+
serious problems when using recursive calls
6+
mandatory context parameters:
7+
schema
8+
#}
9+
{# context parameters default values #}
10+
{% set skip_headers = skip_headers or False %}
11+
{% set depth = depth or 0 %}
12+
{# end context parameters #}
13+
14+
{% set keys = schema.keywords %}
15+
{%- if not skip_headers %}
16+
17+
{% if schema.title and schema.title | length > 0 %}
18+
**Title:** {{ schema.title }}
19+
{% endif %}
20+
21+
{% set description = (schema | get_description) %}
22+
{% include "section_description.md" %}
23+
24+
{{ schema | md_type_info_table | md_generate_table }}
25+
26+
{% endif %}
27+
28+
{% if schema.should_be_a_link(config) %}
29+
{% elif schema.refers_to -%}
30+
{%- with schema=schema.refers_to_merged, skip_headers=True, depth=depth -%}
31+
{% include "content.md" %}
32+
{% endwith %}
33+
{% else %}
34+
35+
{# Combining: allOf, anyOf, oneOf, not #}
36+
{% if schema.kw_all_of %}
37+
{% with operator="allOf", title="All of(Requirement)", current_node=schema.kw_all_of, skip_required=True %}
38+
{% include "tabbed_section.md" %}
39+
{% endwith %}
40+
{% endif %}
41+
{% if schema.kw_any_of %}
42+
{% with operator="anyOf", title="Any of(Option)", current_node=schema.kw_any_of, skip_required=True %}
43+
{% include "tabbed_section.md" %}
44+
{% endwith %}
45+
{% endif %}
46+
{% if schema.kw_one_of %}
47+
{% with operator="oneOf", title="One of(Option)",current_node=schema.kw_one_of, skip_required=True %}
48+
{% include "tabbed_section.md" %}
49+
{% endwith %}
50+
{% endif %}
51+
{% if schema.kw_not %}
52+
{% include "section_not.md" %}
53+
{% endif %}
54+
55+
{# Enum and const #}
56+
{% if schema.kw_enum -%}
57+
{% include "section_one_of.md" %}
58+
{%- endif %}
59+
{%- if schema.kw_const -%}
60+
Specific value: `{{ schema.kw_const.raw | python_to_json }}`
61+
{%- endif -%}
62+
63+
{# Conditional subschema, or if-then-else section #}
64+
{% if schema.has_conditional %}
65+
{% with skip_headers=False, depth=depth+1 %}
66+
{% include "section_conditional_subschema.md" %}
67+
{% endwith %}
68+
{% endif %}
69+
70+
{# Required properties that are not defined under "properties". They will only be listed #}
71+
{% include "section_undocumented_required_properties.md" %}
72+
73+
{# Show the requested type(s) #}
74+
{{- schema | md_restrictions_table | md_generate_table -}}
75+
76+
{# Show array restrictions #}
77+
{% if schema.type_name.startswith("array") %}
78+
{% include "section_array.md" %}
79+
{% endif %}
80+
81+
{# Display examples #}
82+
{% set examples = schema.examples %}
83+
{% if examples %}
84+
{% include "section_examples.md" %}
85+
{% endif %}
86+
87+
{# details of Properties, pattern properties, additional properties #}
88+
{% if schema.type_name == "object" %}
89+
{% with skip_required=False %}
90+
{% include "section_properties_details.md" %}
91+
{% endwith %}
92+
{% endif %}
93+
{% endif %}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{{ schema | md_array_restrictions | md_generate_table }}
2+
3+
{% if schema.array_items_def %} {% filter md_heading(depth+1) %} {% with schema=schema.array_items_def %}{%- include "breadcrumbs.md" %}{% endwith %} {% endfilter %} {% with schema=schema.array_items_def, skip_headers=False, skip_required=True %} {% include "content.md" %} {% endwith %} {% endif %}
4+
5+
{% if schema.kw_items %}
6+
{{ schema | md_array_items_restrictions | md_generate_table }}
7+
8+
{% for item in schema.kw_items %}
9+
{% filter md_heading(depth+1, item.html_id) %}
10+
{% with schema=item %}{%- include "breadcrumbs.md" %}{% endwith %}
11+
{% endfilter %}
12+
{% with schema=item, skip_headers=False, skip_required=True %}
13+
{% include "content.md" %}
14+
{% endwith %}
15+
{% endfor %}
16+
{% endif %}
17+
18+
{% if schema.kw_contains and schema.kw_contains.literal != {} %}
19+
{{ "At least one of the items must be" | md_heading(depth+1) }}
20+
{% with schema=schema.kw_contains, skip_headers=False, skip_required=True %}
21+
{% include "content.md" %}
22+
{% endwith %}
23+
{% endif %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{% if schema.kw_if %}
2+
{% set first_property = schema.kw_if | get_first_property %}
3+
4+
{% if schema.kw_then %}
5+
{%- filter md_heading(depth) -%}If (
6+
{{- first_property.property_name | md_escape_for_table -}}
7+
{{- " = " -}}
8+
{{- first_property.kw_const.literal | python_to_json -}}
9+
){%- endfilter -%}
10+
{% with schema=schema.kw_then, skip_headers=False, depth=depth %}
11+
{% include "content.md" %}
12+
{% endwith %}
13+
{% endif %}
14+
{% if schema.kw_else %}
15+
{%- filter md_heading(depth) -%}Else (i.e. {{ " " }}
16+
{{- first_property.property_name | md_escape_for_table -}}
17+
{{- " != " -}}
18+
{{- first_property.kw_const.literal | python_to_json -}}
19+
){%- endfilter -%}
20+
{% with schema=schema.kw_else, skip_headers=False, depth=depth %}
21+
{% include "content.md" %}
22+
{% endwith %}
23+
{% endif %}
24+
{% endif %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{# Display description #}
2+
{% if description %}
3+
**Description:**{{ " " }}{{ description }}
4+
{% endif %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
**Example{% if examples|length > 1 %}s{% endif %}:**{{ " " }}
2+
3+
{% for example in examples %}
4+
{% set example_id = schema.html_id ~ "_ex" ~ loop.index %}
5+
```json
6+
{{ example }}
7+
```
8+
{% endfor %}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{{ "Must **not** be" | md_heading(depth+1) }}
2+
{% with schema=schema.kw_not, skip_headers=False, depth=depth+1, skip_required=True %}
3+
{% include "content.md" %}
4+
{% endwith %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
:::note
2+
Must be one of:
3+
{% for enum_choice in schema.kw_enum.array_items %}
4+
* {{ enum_choice.literal | python_to_json }}
5+
{% endfor %}
6+
:::
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{% for sub_property in schema.iterate_properties %}
2+
{%- if sub_property.is_additional_properties and not sub_property.is_additional_properties_schema -%}
3+
{% continue %}
4+
{% endif %}
5+
6+
{% set html_id = sub_property.html_id %}
7+
8+
{% set description = sub_property | get_description %}
9+
<details>
10+
<summary>{% filter md_heading(depth + 1, html_id, True) -%}
11+
{%- filter replace('\n', '') -%}
12+
{%- if sub_property is deprecated -%}~~{%- endif -%}
13+
{%- if sub_property.is_pattern_property %} Pattern Property{% endif %} {% with schema=sub_property %}{%- include "breadcrumbs.md" %} {% endwith %}
14+
{%- if not skip_required and sub_property.property_name -%}
15+
{{ "*" if sub_property.is_required_property else "" -}}
16+
{%- endif -%}
17+
{%- if sub_property is deprecated -%}~~{%- endif -%}
18+
{%- endfilter %}
19+
{%- endfilter %}
20+
21+
22+
</summary>
23+
&nbsp;
24+
<blockquote>
25+
26+
{% with schema=sub_property, skip_headers=False %}
27+
{% if sub_property.is_pattern_property %}
28+
:::note
29+
All properties whose name matches the regular expression
30+
```{{ sub_property.property_name }}``` ([Test](https://regex101.com/?regex={{ sub_property.property_name | urlencode }}))
31+
must respect the following conditions
32+
:::
33+
{% endif %}
34+
{%- if not skip_required and sub_property.property_name -%}
35+
{{ md_badge("Required", "red", show_text=False) if sub_property.is_required_property else "" -}}
36+
{%- endif -%}
37+
{% include "content.md" %}
38+
{% endwith %}
39+
40+
</blockquote>
41+
</details>
42+
43+
{% endfor %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{% set undocumented_required_properties = schema | get_undocumented_required_properties %}
2+
{% if undocumented_required_properties%}
3+
{{ "The following properties are required" | md_heading(depth+1) }}
4+
{% for required_property in undocumented_required_properties %}
5+
* {{ required_property }}
6+
{% endfor %}
7+
{% endif %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<blockquote>
2+
3+
{{ current_node | md_array_items(title) | md_generate_table }}
4+
5+
{% for node in current_node.array_items %}
6+
<blockquote>
7+
8+
{% filter md_heading(depth+1, node.html_id) -%}
9+
{% if node.is_pattern_property %}Pattern{% endif %} Property `{% with schema=node %}{%- include "breadcrumbs.md" %}{% endwith %}`
10+
{%- endfilter %}
11+
12+
{% with schema=node, skip_headers=False, depth=depth+1 %}
13+
{% include "content.md" %}
14+
{% endwith %}
15+
16+
</blockquote>
17+
{% endfor %}
18+
19+
</blockquote>

docs/4-user-guide/2-zarf-packages/1-zarf-packages.md

+1-10
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,7 @@ When Zarf is deploying the package, it will use the infrastructure that was crea
6262

6363
## What Makes Up A Package
6464

65-
Zarf packages are split into smaller chunks called 'components'. These components are defined more in the [Zarf Components page](./2-zarf-components.md) but a quick way to understand components are as the actual named capabilities that packages provide. The schema of a zarf.yaml package follows the following format:
66-
67-
```yaml
68-
kind: <STRING> # Either ZarfPackageConfig or ZarfInitConfig
69-
metadata:
70-
name: <STRING> # The name of the package
71-
description: <STRING> # A description of the package
72-
seed: <STRING> # Docker registry to seed the cluster with. Only used for init packages
73-
components: <OBJ LIST> # Components definitions are complex and broken down more in the 'Understanding Zarf Components' page
74-
```
65+
Zarf packages are split into smaller chunks called 'components'. These components are defined more in the [Zarf Components page](./2-zarf-components.md) but a quick way to understand components are as the actual named capabilities that packages provide. The schema of a zarf.yaml package is available here: [ZarfPackage Schema Docs](../3-zarf-schema.md)
7566

7667
<br />
7768
<br />

0 commit comments

Comments
 (0)