diff --git a/EXAMPLE/prometheus-advanced.html b/EXAMPLE/prometheus-advanced.html
index c269008..ca8e877 100644
--- a/EXAMPLE/prometheus-advanced.html
+++ b/EXAMPLE/prometheus-advanced.html
@@ -5,113 +5,248 @@
prometheus - helm chart documentation
diff --git a/EXAMPLE/prometheus.html b/EXAMPLE/prometheus.html
index 80d708b..56fe7e3 100644
--- a/EXAMPLE/prometheus.html
+++ b/EXAMPLE/prometheus.html
@@ -6,41 +6,247 @@
prometheus - helm chart documentation
diff --git a/EXAMPLE/style.css b/EXAMPLE/style.css
index cd2131f..706d3bd 100644
--- a/EXAMPLE/style.css
+++ b/EXAMPLE/style.css
@@ -1,36 +1,242 @@
-body {
- font-family: sans-serif;
- margin: auto;
- padding: 10px;
- max-width: 80%;
+html {
+ --blue: #A8DADC; /* Pastel Cyan */
+ --dark-blue: #457B9D; /* Steel Blue */
+ --light-blue: #F1FAEE; /* Honeydew */
+ --light-gray: #F8F9FA; /* Light Gray */
+ --gray: #D8E2DC; /* Soft Gray */
+ --dark-gray: #264653; /* Deep Green */
+ --dark-bg: #343A40; /* Charcoal */
+ --dark-card-bg: #495057; /* Granite */
+ --dark-text: #E9ECEF; /* Light Gray Text for Dark Mode */
+ --darker-text: #121212; /* Dark text for Dark Mode */
+ --dark-gray-text: #264653; /* Deep Green for Dark Mode Text */
+ --dark-link: #A8DADC; /* Pastel Cyan for Links */
+ --dark-link-hover: #81B1BD; /* Steel Blue for Hover */
+ --primary-gradient: linear-gradient(135deg, #A8DADC, #F1FAEE); /* Cyan to Honeydew */
+ --secondary-gradient: linear-gradient(135deg, #457B9D, #A8DADC); /* Steel Blue to Cyan */
+ --margin-top: 3em;
+ --border-radius: 15px;
+}
+
+body, html {
+ height: 100%;
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ background-color: var(--light-gray);
+ color: var(--dark-gray);
+ transition: all 0.3s;
+}
+
+#navbar-outer {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: auto;
+ background: var(--secondary-gradient);
+ overflow-x: hidden;
+ margin-top: 0;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ z-index: 1000;
+ transition: all 0.3s;
+}
+
+#navbar, .container {
+ max-width: 80%;
+ margin: auto;
+}
+
+#navbar a {
+ padding: 1em;
+ text-decoration: none;
+ color: var(--light-gray);
+ display: inline-block;
+ transition: background-color 0.3s, transform 0.3s;
+ border-radius: var(--border-radius);
+}
+
+#navbar a:first-child {
+ background: var(--primary-gradient);
+ font-weight: bold;
+ color: var(--dark-gray);
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+
+#navbar a:hover {
+ background: var(--primary-gradient);
+ transform: translateY(-2px);
+ color: var(--dark-gray);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
+}
+
+#search {
+ position: relative;
+ padding: 15px;
+ width: 98%;
+ margin: 20px auto;
+ display: block;
+ font-size: medium;
+ color: var(--dark-gray);
+ border: none;
+ border-radius: var(--border-radius);
+ background: var(--light-gray);
+ box-shadow: inset 6px 6px 12px #ccc, inset -6px -6px 12px #fff;
+ transition: all 0.3s;
+}
+
+#search:focus {
+ box-shadow: inset 6px 6px 12px #bbb, inset -6px -6px 12px #eee, 0 0 8px 2px rgba(248, 241, 225, 0.5);
+ outline: none;
+}
+
+.content {
+ padding: 25px;
+ margin-top: var(--margin-top);
+ background-color: white;
+ border-radius: var(--border-radius);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ transition: all 0.3s;
+ background: var(--light-gray);
+}
+
+.container {
+ padding: 25px;
+ border-radius: var(--border-radius);
+ box-shadow: 4px 4px 8px #ccc, -4px -4px 8px #fff;
+ background-color: var(--light-gray);
+ transition: all 0.3s;
+}
+
+.table-container {
+ padding: 0 1em;
+ overflow: auto;
}
table {
- font-family: Arial, Helvetica, sans-serif;
- border-collapse: collapse;
- display: block;
- overflow-x: auto;
+ border-collapse: collapse;
+ width: 100%;
+ background-color: white;
+ border-radius: var(--border-radius);
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
+ margin-bottom: 20px;
+ overflow: hidden;
+ transition: all 0.3s;
}
td, th {
- border: 1px solid #ddd;
- padding: 8px;
+ border: 1px solid var(--gray);
+ padding: 12px;
+ transition: background-color 0.3s;
}
-tr:nth-child(even){background-color: #f2f2f2;}
+tr:nth-child(even) {
+ background-color: #E9ECEF; /* Soft Light Gray */
+}
-tr:hover {background-color: #E0F2FF;}
+tr:hover {
+ background-color: #D8E2DC; /* Very Soft Gray */
+}
th {
- padding-top: 12px;
- padding-bottom: 12px;
- text-align: left;
- background-color: #0288d1;
- color: white;
+ padding-top: 14px;
+ padding-bottom: 14px;
+ text-align: left;
+ background: var(--secondary-gradient);
+ color: var(--light-gray);
}
pre {
background-color: #E4E4E4;
- padding: 0.5em;
- border-radius: 5px;
+ padding: 15px;
+ border-radius: var(--border-radius);
+ overflow-x: auto;
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
+ transition: all 0.3s;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ scroll-margin-top: var(--margin-top);
+ color: var(--dark-gray);
+ transition: color 0.3s;
+}
+
+/* Dark Mode */
+@media (prefers-color-scheme: dark) {
+ body, html {
+ background-color: var(--dark-bg);
+ color: var(--dark-text);
+ }
+
+ #navbar-outer {
+ background: var(--primary-gradient);
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.5);
+ }
+
+ #navbar a {
+ color: var(--dark-gray-text); /* Make navbar links text darker */
+ }
+
+ #navbar a:first-child {
+ background: var(--secondary-gradient);
+ color: var(--light-gray);
+ }
+
+ #navbar a:hover {
+ background: var(--secondary-gradient);
+ color: var(--light-gray);
+ }
+
+ #search {
+ background: var(--dark-card-bg);
+ color: var(--dark-text);
+ box-shadow: inset 6px 6px 12px #292d31, inset -6px -6px 12px #5a616a;
+ }
+
+ #search:focus {
+ box-shadow: inset 6px 6px 12px #292d31, inset -6px -6px 12px #5a616a, 0 0 8px 2px rgba(168, 218, 220, 0.5);
+ }
+
+ .content, .container {
+ background: var(--dark-card-bg);
+ box-shadow: 4px 4px 8px #292d31, -4px -4px 8px #5a616a;
+ }
+
+ table {
+ background-color: var(--dark-card-bg);
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
+ }
+
+ td, th {
+ border: 1px solid #555;
+ }
+
+ tr:nth-child(even) {
+ background-color: #42474d; /* Dark Granite */
+ }
+
+ tr:hover {
+ background-color: #3c3f41; /* Slightly lighter dark granite */
+ }
+
+ th {
+ background: var(--primary-gradient);
+ color: var(--dark-gray-text); /* Make table header text darker */
+ }
+
+ pre {
+ background-color: #333;
+ }
+
+ h1, h2, h3, h4, h5, h6 {
+ color: var(--light-blue);
+ }
+
+ a {
+ color: var(--dark-link);
+ transition: color 0.3s;
+ }
+
+ a:hover {
+ color: var(--dark-link-hover);
+ }
}
diff --git a/README.md b/README.md
index 481eb92..cd2f5dc 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ helm chart, follow these links:
## Usage
-### Docker Image
+### 🐳 Docker Image
| | Note |
@@ -46,7 +46,7 @@ docker run -v ${full_path_to_host_chart_dir}:/tmp/chart ghcr.io/very-doge-wow/st
```
-### Installation
+### 🛠 Installation
To run it natively on your machine using pipenv:
@@ -66,7 +66,7 @@ pip install pyyaml markdown
python stella.py --help
```
-### General Usage
+### 📚 General Usage
```text
@@ -94,7 +94,7 @@ additional functionality which would break when using custom CSS. It will
create a static html site with dynamic navbar and a search for the chart's
values.
-## Adding `stella` Docstrings to your Chart
+## ⎈ Adding `stella` Docstrings to your Chart
Metadata is read from the present files of your chart.
Additionally, you should also document the options given
@@ -155,7 +155,7 @@ Will yield the output:
-## Custom Templating
+## 📄 Custom Templating
To specify a custom template, create a text/markdown file, then pass it to
stella using the config parameter.
@@ -172,14 +172,14 @@ You can use the following fields inside your template:
* `{{ stella.objects }}`
* `{{ stella.values }}`
-## Contributing to `stella`
+## 💫 Contributing to `stella`
You want to contribute? Awesome!
Feel free to propose changes, report bugs or request features and
improvements. But first, please read the
[contribution guidelines](https://github.com/very-doge-wow/stella/blob/main/CONTRIBUTING.md).
-## Why `stella`?
+## 💭 Why `stella`?
`stella` is named after
[Tilemann Stella](https://de.wikipedia.org/wiki/Tilemann_Stella),
@@ -187,3 +187,57 @@ a scholar from the Renaissance era.
He is most famously known for being a cartographer and for creating
multiple waterways, which is fitting when considering the tool should
create helm chart docs.
+
+## 🧑💻 Development
+
+
+
+Expand for more info
+
+### Linting Code
+
+Install linters beforehand:
+
+* [markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli)
+* [ruff](https://docs.astral.sh/ruff/)
+
+```shell
+# Markdown Linter
+markdownlint './*.md' \
+ --ignore './test/output.md' \
+ --ignore './test/custom-template-keywords.md' \
+ --ignore './EXAMPLE_OUTPUT.md'
+
+# Python Linter
+ruff check \
+ --fix \
+ --config "lint.extend-select=['E','F','B','Q','S','W','DJ']" .
+```
+
+### Running Unit Tests
+
+```shell
+pipenv install -d
+pipenv run pytest -vv --cov --cov-report=xml
+```
+
+### Updating Example Outputs
+
+```shell
+pipenv install
+
+pipenv run python stella.py \
+ -fh \
+ -css EXAMPLE/style.css \
+ -hcp EXAMPLE/prometheus \
+ -o EXAMPLE/prometheus.html
+
+pipenv run python stella.py \
+ -fh \
+ --advanced-html \
+ -hcp EXAMPLE/prometheus \
+ -o EXAMPLE/prometheus-advanced.html
+```
+
+
+
diff --git a/reader/chart_reader.py b/reader/chart_reader.py
index c6cc9a2..e8e5860 100644
--- a/reader/chart_reader.py
+++ b/reader/chart_reader.py
@@ -81,7 +81,7 @@ def get_value_from_yaml(parsed_yaml: dict, full_path: str) -> dict:
Returns:
result (dict): Generated data structure.
"""
- keys = full_path.split('.') # Split the full path into individual keys
+ keys = full_path.split(".") # Split the full path into individual keys
result = {} # Initialize an empty dictionary to store the result
current = result # Set a pointer to the beginning of the result dictionary
for key in keys[:-1]: # Iterate over each key except the last one
@@ -98,7 +98,7 @@ def get_value_from_yaml(parsed_yaml: dict, full_path: str) -> dict:
elif isinstance(value, list) and not value:
current[keys[-1]] = [] # Set the value if it's an empty list
elif isinstance(value, str) and not value.strip():
- current[keys[-1]] = '' # Set the value if it's an empty string or contains only whitespace
+ current[keys[-1]] = "" # Set the value if it's an empty string or contains only whitespace
else:
current[keys[-1]] = value # Otherwise, set the value as is
else:
@@ -124,18 +124,18 @@ def build_full_path(i: int, value_name_dirty: str, value_name_clean: str, values
# first element will always be the current key's name
full_path = value_name_clean
# check if whitespace before key is found
- match = re.search(r'^(\s+).*$', value_name_dirty)
+ match = re.search(r"^(\s+).*$", value_name_dirty)
# if already on top-level, we are done here
if not match:
return full_path
# save original indent to compare against it below
- initial_indent = match.group(0).count(' ')
+ initial_indent = match.group(0).count(" ")
index = i
# save all indents to which a key was already added to full_path, as only one can exist for each indent
matched_indents = []
while match:
# count the indent
- indent_num = match.group(0).count(' ')
+ indent_num = match.group(0).count(" ")
# early exit if already on toplevel
if indent_num == 0:
return f"{upper_key}.{full_path}"
@@ -150,14 +150,14 @@ def build_full_path(i: int, value_name_dirty: str, value_name_clean: str, values
# index now points to the line with the key
value_name_dirty = values_lines[index].split(":")[0]
upper_key = value_name_dirty.strip()
- match_new = re.search(r'^\s+', value_name_dirty)
+ match_new = re.search(r"^\s+", value_name_dirty)
if match_new:
- indent_num_new = match_new.group(0).count(' ')
+ indent_num_new = match_new.group(0).count(" ")
# make sure the found key is actually closer to top-level than the first one by counting indent
if indent_num > indent_num_new and initial_indent > indent_num_new and (indent_num_new not in matched_indents):
full_path = f"{upper_key}.{full_path}"
matched_indents.append(indent_num_new)
- match = re.search(r'^\s*', value_name_dirty)
+ match = re.search(r"^\s*", value_name_dirty)
return full_path
@@ -185,8 +185,8 @@ def generate_values_doc(doc: dict, helm_chart_path: str) -> dict:
if stella in line:
# found a stella doc string
# get the indent
- match = re.search(r'^(\s+).*$', line)
- indent_num = match.group(0).count(' ')-1 if match else 0
+ match = re.search(r"^(\s+).*$", line)
+ indent_num = match.group(0).count(" ")-1 if match else 0
doc_string = ""
i = index
# check if the next line still is a comment, if so add it to docstring
@@ -316,7 +316,7 @@ def generate_objects(doc: dict, helm_chart_path: str) -> dict:
if obj != "" and type(obj) == str:
doc["objects"].append({
"kind": obj,
- "from Template": tmpl['path']
+ "from Template": tmpl["path"]
})
logging.debug("done generating objects doc")
diff --git a/reader/chart_reader_test.py b/reader/chart_reader_test.py
index fad871a..ea001b4 100644
--- a/reader/chart_reader_test.py
+++ b/reader/chart_reader_test.py
@@ -1,4 +1,3 @@
-import unittest
import yaml
@@ -25,45 +24,45 @@ def test_read():
result["objects"] = sorted(result["objects"], key=lambda item: item.get("kind"))
result["templates"] = sorted(result["templates"], key=lambda item: item.get("path"))
assert_that(result, has_entries(
- {'name': 'test-chart', 'appVersion': '1.16.0', 'apiVersion': 'v2', 'version': '0.1.0',
- 'description': 'A Helm chart for Kubernetes', 'type': 'application', 'dependencies': [
- {'name': 'postgresql', 'condition': 'postgresql.enabled', 'version': '1.2.3',
- 'repository': 'https://lol.de/repo/'},
- {'name': 'mysql', 'condition': 'mysql.enabled', 'version': '1.2.3', 'repository': 'https://lol.de/repo/'}],
- 'values': [
- {'name': 'affinity',
- 'description': '',
- 'default': {'affinity': {}}, 'example': ''},{'name': 'autoscaling', 'description': '', 'default':
- {'autoscaling': {'enabled': False, 'minReplicas': 1, 'maxReplicas': 100,
- 'targetCPUUtilizationPercentage': 80}}, 'example': ''},
- {'name': 'fullnameOverride', 'description': '', 'default': {'fullnameOverride': ''},
- 'example': ''}, {'name': 'image', 'description': 'which image to deploy\n', 'default':
- {'image': {'repository': 'nginx', 'pullPolicy': 'IfNotPresent', 'tag': ''}}, 'example':
+ {"name": "test-chart", "appVersion": "1.16.0", "apiVersion": "v2", "version": "0.1.0",
+ "description": "A Helm chart for Kubernetes", "type": "application", "dependencies": [
+ {"name": "postgresql", "condition": "postgresql.enabled", "version": "1.2.3",
+ "repository": "https://lol.de/repo/"},
+ {"name": "mysql", "condition": "mysql.enabled", "version": "1.2.3", "repository": "https://lol.de/repo/"}],
+ "values": [
+ {"name": "affinity",
+ "description": "",
+ "default": {"affinity": {}}, "example": ""},{"name": "autoscaling", "description": "", "default":
+ {"autoscaling": {"enabled": False, "minReplicas": 1, "maxReplicas": 100,
+ "targetCPUUtilizationPercentage": 80}}, "example": ""},
+ {"name": "fullnameOverride", "description": "", "default": {"fullnameOverride": ""},
+ "example": ""}, {"name": "image", "description": "which image to deploy\n", "default":
+ {"image": {"repository": "nginx", "pullPolicy": "IfNotPresent", "tag": ""}}, "example":
'\nimage:\n repository: very-doge-wow/stella\n pullPolicy: IfNotPresent\n tag: "latest"\n'},
- {'name': 'imagePullSecrets', 'description': '', 'default': {'imagePullSecrets': []}, 'example': ''},
- {'name': 'ingress', 'description': '', 'default': {'ingress': {'enabled': False, 'className': '',
- 'annotations': {}, 'hosts': [{'host': 'chart-example.local', 'paths':
- [{'path': '/', 'pathType': 'ImplementationSpecific'}]}], 'tls': []}}, 'example': ''},
- {'name': 'nameOverride', 'description': '', 'default': {'nameOverride': ''}, 'example': ''},
- {'name': 'nodeSelector', 'description': '', 'default': {'nodeSelector': {}}, 'example': ''},
- {'name': 'podAnnotations', 'description': '', 'default': {'podAnnotations': {}}, 'example': ''},
- {'name': 'podSecurityContext', 'description': '', 'default': {'podSecurityContext': {}}, 'example': ''},
- {'name': 'replicaCount', 'description': 'how many replicas to deploy\n', 'default':
- {'replicaCount': 1}, 'example': ''}, {'name': 'resources', 'description': '', 'default':
- {'resources': {}}, 'example': ''}, {'name': 'securityContext', 'description': '',
- 'default': {'securityContext': {}}, 'example': ''}, {'name': 'service', 'description': '',
- 'default': {'service': {'type': 'ClusterIP', 'port': 80}}, 'example': ''},
- {'name': 'serviceAccount', 'description': '', 'default': {'serviceAccount':
- {'create': True, 'annotations': {}, 'name': ''}}, 'example': ''},
- {'name': 'tolerations', 'description': '', 'default': {'tolerations': []}, 'example': ''}],
- 'templates': [{'path': 'deployment.yaml'}, {'path': 'hpa.yaml'}, {'path': 'ingress.yaml'},
- {'path': 'service.yaml'}, {'path': 'serviceaccount.yaml'}],
- 'objects': [{'kind': 'Deployment', 'from Template': 'deployment.yaml'},
- {'kind': 'HorizontalPodAutoscaler', 'from Template': 'hpa.yaml'},
- {'kind': 'Ingress', 'from Template': 'ingress.yaml'},
- {'kind': 'Service', 'from Template': 'service.yaml'},
- {'kind': 'ServiceAccount', 'from Template': 'serviceaccount.yaml'}],
- 'commands': [{'description': '', 'command': ''}]}
+ {"name": "imagePullSecrets", "description": "", "default": {"imagePullSecrets": []}, "example": ""},
+ {"name": "ingress", "description": "", "default": {"ingress": {"enabled": False, "className": "",
+ "annotations": {}, "hosts": [{"host": "chart-example.local", "paths":
+ [{"path": "/", "pathType": "ImplementationSpecific"}]}], "tls": []}}, "example": ""},
+ {"name": "nameOverride", "description": "", "default": {"nameOverride": ""}, "example": ""},
+ {"name": "nodeSelector", "description": "", "default": {"nodeSelector": {}}, "example": ""},
+ {"name": "podAnnotations", "description": "", "default": {"podAnnotations": {}}, "example": ""},
+ {"name": "podSecurityContext", "description": "", "default": {"podSecurityContext": {}}, "example": ""},
+ {"name": "replicaCount", "description": "how many replicas to deploy\n", "default":
+ {"replicaCount": 1}, "example": ""}, {"name": "resources", "description": "", "default":
+ {"resources": {}}, "example": ""}, {"name": "securityContext", "description": "",
+ "default": {"securityContext": {}}, "example": ""}, {"name": "service", "description": "",
+ "default": {"service": {"type": "ClusterIP", "port": 80}}, "example": ""},
+ {"name": "serviceAccount", "description": "", "default": {"serviceAccount":
+ {"create": True, "annotations": {}, "name": ""}}, "example": ""},
+ {"name": "tolerations", "description": "", "default": {"tolerations": []}, "example": ""}],
+ "templates": [{"path": "deployment.yaml"}, {"path": "hpa.yaml"}, {"path": "ingress.yaml"},
+ {"path": "service.yaml"}, {"path": "serviceaccount.yaml"}],
+ "objects": [{"kind": "Deployment", "from Template": "deployment.yaml"},
+ {"kind": "HorizontalPodAutoscaler", "from Template": "hpa.yaml"},
+ {"kind": "Ingress", "from Template": "ingress.yaml"},
+ {"kind": "Service", "from Template": "service.yaml"},
+ {"kind": "ServiceAccount", "from Template": "serviceaccount.yaml"}],
+ "commands": [{"description": "", "command": ""}]}
))
@@ -71,12 +70,12 @@ def test_generate_chart_metadata_real_file():
result = chart_reader.generate_chart_metadata({}, "test/test-chart")
assert_that(result, has_entries(
{
- 'apiVersion': 'v2',
- 'appVersion': '1.16.0',
- 'description': 'A Helm chart for Kubernetes',
- 'name': 'test-chart',
- 'type': 'application',
- 'version': '0.1.0'
+ "apiVersion": "v2",
+ "appVersion": "1.16.0",
+ "description": "A Helm chart for Kubernetes",
+ "name": "test-chart",
+ "type": "application",
+ "version": "0.1.0"
}
))
@@ -89,12 +88,12 @@ def test_generate_chart_metadata_unknown():
chart_reader.yaml.safe_load = real_yaml_load
assert_that(result, has_entries(
{
- 'apiVersion': 'unknown',
- 'appVersion': 'unknown',
- 'description': 'unknown',
- 'name': 'unknown',
- 'type': 'unknown',
- 'version': 'unknown'
+ "apiVersion": "unknown",
+ "appVersion": "unknown",
+ "description": "unknown",
+ "name": "unknown",
+ "type": "unknown",
+ "version": "unknown"
}
))
@@ -116,15 +115,15 @@ def test_generate_values_doc_and_example():
result = chart_reader.generate_values_doc(doc, "test/values-stella")
assert_that(result["values"], contains_inanyorder(
{
- 'name': 'replicaCount',
- 'description': 'how many replicas to deploy\n',
- 'default': {'replicaCount': 1}, 'example': ''
+ "name": "replicaCount",
+ "description": "how many replicas to deploy\n",
+ "default": {"replicaCount": 1}, "example": ""
},
{
- 'name': 'image',
- 'description': 'which image to deploy\n',
- 'default': {'image': {'repository': 'nginx', 'pullPolicy': 'IfNotPresent', 'tag': ''}},
- 'example': '\nimage:\n repository: very-doge-wow/stella\n pullPolicy: IfNotPresent\n tag: "latest"\n'
+ "name": "image",
+ "description": "which image to deploy\n",
+ "default": {"image": {"repository": "nginx", "pullPolicy": "IfNotPresent", "tag": ""}},
+ "example": '\nimage:\n repository: very-doge-wow/stella\n pullPolicy: IfNotPresent\n tag: "latest"\n'
}
))
@@ -146,9 +145,9 @@ def test_generate_values_doc_only():
result = chart_reader.generate_values_doc(doc, "test/values-stella-only")
assert_that(result["values"], contains_inanyorder(
{
- 'name': 'replicaCount',
- 'description': 'how many replicas to deploy\n',
- 'default': {'replicaCount': 1}, 'example': ''
+ "name": "replicaCount",
+ "description": "how many replicas to deploy\n",
+ "default": {"replicaCount": 1}, "example": ""
}
))
@@ -169,7 +168,7 @@ def test_generate_values_pipes_in_tables():
}
result = chart_reader.generate_values_doc(doc, "test/values-pipes")
assert_that(result["values"], contains_inanyorder(
- {'name': 'customObjects', 'description': 'Test for using pipes in examples\n', 'default': {'customObjects': []}, 'example': '\ncustomObjects:\n - \\|\n best-string\n'}
+ {"name": "customObjects", "description": "Test for using pipes in examples\n", "default": {"customObjects": []}, "example": "\ncustomObjects:\n - \\|\n best-string\n"}
))
@@ -190,8 +189,8 @@ def test_generate_values_comments_in_examples():
result = chart_reader.generate_values_doc(doc, "test/values-comments-examples")
print(result)
assert_that(result["values"], contains_inanyorder(
- {'name': 'best', 'description': 'Test for comments in examples\n', 'default': {'best': []},
- 'example': '\nbest:\n # this is a comment inside an example\n - value\n'}
+ {"name": "best", "description": "Test for comments in examples\n", "default": {"best": []},
+ "example": "\nbest:\n # this is a comment inside an example\n - value\n"}
))
@@ -212,7 +211,7 @@ def test_generate_values_docs_nested():
result = chart_reader.generate_values_doc(doc, "test/values-nested-docs")
print(result)
assert_that(result["values"], contains_inanyorder(
- {'name': 'image', 'description': 'which image to deploy\n', 'default': {'image': {'repository': 'nginx', 'pullPolicy': 'IfNotPresent', 'tag': ''}}, 'example': '\nimage:\n repository: very-doge-wow/stella\n pullPolicy: IfNotPresent\n'}, {'name': 'image.tag', 'description': 'Overrides the image tag whose default is the chart appVersion.\n', 'default': {'image': {'tag': ''}}, 'example': '\nimage:\n tag: "latest"\n'}, {'name': 'replicaCount', 'description': 'how many replicas to deploy\n', 'default': {'replicaCount': 1}, 'example': ''}
+ {"name": "image", "description": "which image to deploy\n", "default": {"image": {"repository": "nginx", "pullPolicy": "IfNotPresent", "tag": ""}}, "example": "\nimage:\n repository: very-doge-wow/stella\n pullPolicy: IfNotPresent\n"}, {"name": "image.tag", "description": "Overrides the image tag whose default is the chart appVersion.\n", "default": {"image": {"tag": ""}}, "example": '\nimage:\n tag: "latest"\n'}, {"name": "replicaCount", "description": "how many replicas to deploy\n", "default": {"replicaCount": 1}, "example": ""}
))
@@ -405,44 +404,44 @@ def test_build_full_path():
# desc
getme: true
"""
- result = chart_reader.build_full_path(i=3, value_name_dirty=' another', value_name_clean='another',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=3, value_name_dirty=" another", value_name_clean="another",
+ values_lines=test_yaml.split("\n"))
assert result == "first.another"
- result = chart_reader.build_full_path(i=2, value_name_dirty=' element', value_name_clean='element',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=2, value_name_dirty=" element", value_name_clean="element",
+ values_lines=test_yaml.split("\n"))
assert result == "first.element"
- result = chart_reader.build_full_path(i=5, value_name_dirty='emptydict', value_name_clean='emptydict',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=5, value_name_dirty="emptydict", value_name_clean="emptydict",
+ values_lines=test_yaml.split("\n"))
assert result == "emptydict"
- result = chart_reader.build_full_path(i=5, value_name_dirty='emptyarray', value_name_clean='emptyarray',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=5, value_name_dirty="emptyarray", value_name_clean="emptyarray",
+ values_lines=test_yaml.split("\n"))
assert result == "emptyarray"
- result = chart_reader.build_full_path(i=9, value_name_dirty='yet', value_name_clean='yet',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=9, value_name_dirty="yet", value_name_clean="yet",
+ values_lines=test_yaml.split("\n"))
assert result == "yet"
- result = chart_reader.build_full_path(i=10, value_name_dirty=' another', value_name_clean='another',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=10, value_name_dirty=" another", value_name_clean="another",
+ values_lines=test_yaml.split("\n"))
assert result == "yet.another"
- result = chart_reader.build_full_path(i=14, value_name_dirty=' drei', value_name_clean='drei',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=14, value_name_dirty=" drei", value_name_clean="drei",
+ values_lines=test_yaml.split("\n"))
assert result == "eins.zwei.drei"
- result = chart_reader.build_full_path(i=16, value_name_dirty=' fuenf', value_name_clean='fuenf',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=16, value_name_dirty=" fuenf", value_name_clean="fuenf",
+ values_lines=test_yaml.split("\n"))
assert result == "eins.zwei.vier.fuenf"
- result = chart_reader.build_full_path(i=18, value_name_dirty=' sechs', value_name_clean='sechs',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=18, value_name_dirty=" sechs", value_name_clean="sechs",
+ values_lines=test_yaml.split("\n"))
assert result == "eins.sechs"
- result = chart_reader.build_full_path(i=29, value_name_dirty=' getme', value_name_clean='getme',
- values_lines=test_yaml.split('\n'))
+ result = chart_reader.build_full_path(i=29, value_name_dirty=" getme", value_name_clean="getme",
+ values_lines=test_yaml.split("\n"))
assert result == "banane.test.getme"
diff --git a/stella.py b/stella.py
index 0c351b1..6d99983 100755
--- a/stella.py
+++ b/stella.py
@@ -1,12 +1,11 @@
#! /usr/local/bin/python3
import argparse
import logging
-import os
import reader.chart_reader as chart_reader
import writer.doc_writer as doc_writer
-if __name__ == '__main__':
+if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Will create documentation for helm charts using metadata.")
parser.add_argument("-hcp", "--helm-chart-path", help="Path to helm chart (default `.`).", required=False, default=".")
parser.add_argument("-o", "--output", help="Output file (default `output.md`).", required=False, default="output.md")
@@ -40,14 +39,14 @@
try:
# read all necessary metadata
result = chart_reader.read(args.helm_chart_path)
-
+
# fix file ending for case format html
if args.format_html and args.output.endswith(".md"):
args.output = args.output.replace(".md", ".html")
# write doc from gathered data
doc_writer.write(output=args.output, doc=result, template=args.template, format_html=args.format_html, advanced_html=args.advanced_html, css=args.css)
- except Exception as err:
+ except Exception:
logging.exception("Error occurred.")
exit(1)
diff --git a/writer/doc_writer.py b/writer/doc_writer.py
index cf309eb..d0934fa 100644
--- a/writer/doc_writer.py
+++ b/writer/doc_writer.py
@@ -113,113 +113,248 @@ def write(output: str, doc: dict, template: str, format_html: bool, advanced_htm
REPLACE_STRING_TITLE
@@ -385,7 +520,7 @@ def translate_list_of_dicts_to_md(list_of_dicts: list) -> str:
def count_lines(text):
# Split the text by newline characters
- lines = text.split('\n')
+ lines = text.split("\n")
# Count the number of lines
return len(lines)
diff --git a/writer/doc_writer_test.py b/writer/doc_writer_test.py
index 3352022..d990cb7 100644
--- a/writer/doc_writer_test.py
+++ b/writer/doc_writer_test.py
@@ -487,113 +487,248 @@ def test_writer_advanced_html():
unittest - helm chart documentation