helmgen 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
helmgen/__init__.py ADDED
@@ -0,0 +1,18 @@
1
+ """
2
+ HelmGen — Auto-generate Helm charts from Docker Compose files.
3
+
4
+ This package provides:
5
+ - A CLI entry point (helmgen)
6
+ - A generator that parses docker-compose.yml
7
+ - Template rendering for Helm charts
8
+
9
+ Author: Marcelo Garcia
10
+ License: MIT
11
+ """
12
+
13
+ __version__ = "0.1.0"
14
+
15
+ from .generator import main
16
+
17
+ if __name__ == "__main__":
18
+ main()
helmgen/__main__.py ADDED
@@ -0,0 +1,8 @@
1
+ """
2
+ Entry point for running `python -m helmgen`
3
+ """
4
+
5
+ from .generator import main
6
+
7
+ if __name__ == "__main__":
8
+ main()
helmgen/generator.py ADDED
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import re
4
+ import sys
5
+ import yaml
6
+ import argparse
7
+ from pathlib import Path
8
+ import importlib.resources as pkg_resources
9
+ import shutil
10
+ from shutil import copyfile
11
+
12
+ # -------------------------------------------------------------------
13
+ # Locate Helm templates robustly (works in dev mode and installed pkg)
14
+ # -------------------------------------------------------------------
15
+ def get_template_dir() -> Path:
16
+ """
17
+ Locate the helm_templates directory whether running from source
18
+ or from an installed package.
19
+ """
20
+ # Try to resolve from package resources (works after install)
21
+ try:
22
+ return Path(pkg_resources.files("helmgen") / "helm_templates")
23
+ except Exception:
24
+ # Fallback for local dev execution
25
+ return Path(__file__).parent / "helm_templates"
26
+
27
+ TEMPLATE_DIR = get_template_dir()
28
+
29
+ # -------------------------------
30
+ # Utility helpers
31
+ # -------------------------------
32
+
33
+ SENSITIVE_KEYS = [
34
+ "PASSWORD", "PASS", "SECRET", "KEY", "TOKEN", "CREDENTIAL"
35
+ ]
36
+
37
+ BASE_HELM_TEMPLATES = [
38
+ "deployment.yaml",
39
+ "service.yaml",
40
+ "pvc.yaml",
41
+ "ingress.yaml",
42
+ "secrets.yaml",
43
+ "externalsecret.yaml",
44
+ "secretstore.yaml",
45
+ ]
46
+
47
+ DEFAULT_STORAGE_SIZES = {
48
+ "postgres": "5Gi",
49
+ "mysql": "5Gi",
50
+ "mariadb": "5Gi",
51
+ "mongodb": "5Gi",
52
+ "redis": "1Gi",
53
+ }
54
+
55
+ # -------------------------------
56
+ # Core logic
57
+ # -------------------------------
58
+
59
+ def is_database(image):
60
+ db_keywords = ["postgres", "mysql", "mariadb", "mongodb", "redis"]
61
+ return any(k in image.lower() for k in db_keywords)
62
+
63
+ def detect_sensitive_env(env_dict):
64
+ sensitive = {}
65
+ normal = {}
66
+ for k, v in env_dict.items():
67
+ if any(s in k.upper() for s in SENSITIVE_KEYS):
68
+ sensitive[k] = "<secret-from-values>"
69
+ else:
70
+ normal[k] = v
71
+ return normal, sensitive
72
+
73
+ def detect_ingress(service):
74
+ ingress = None
75
+ ports = service.get("ports", [])
76
+ labels = service.get("labels", {})
77
+ host = None
78
+ tls = False
79
+
80
+ for p in ports:
81
+ port_num = None
82
+ if isinstance(p, str):
83
+ parts = p.split(":")
84
+ try:
85
+ port_num = int(parts[-1])
86
+ except ValueError:
87
+ continue
88
+ elif isinstance(p, dict):
89
+ port_num = p.get("target") or p.get("published") or p.get("containerPort")
90
+
91
+ if port_num and int(port_num) in [80, 443, 8080]:
92
+ ingress = ingress or {}
93
+ ingress.setdefault("rules", [])
94
+ ingress["rules"].append({
95
+ "host": "example.local",
96
+ "path": "/",
97
+ "port": port_num,
98
+ })
99
+ if int(port_num) == 443:
100
+ tls = True
101
+
102
+ for key, val in labels.items():
103
+ if "Host:" in val:
104
+ host_match = re.search(r"Host:([^\s,;]+)", val)
105
+ if host_match:
106
+ host = host_match.group(1)
107
+ elif "Host(" in val:
108
+ host_match = re.search(r"Host\(`?([^)]+)`?\)", val)
109
+ if host_match:
110
+ host = host_match.group(1)
111
+ elif key in ["ingress.host", "ingress.domain"]:
112
+ host = val
113
+
114
+ if host:
115
+ ingress = ingress or {}
116
+ if "rules" not in ingress or not ingress["rules"]:
117
+ ingress["rules"] = [{"host": host, "path": "/", "port": 80}]
118
+ else:
119
+ for rule in ingress["rules"]:
120
+ rule["host"] = host
121
+
122
+ if tls or any("tls" in k.lower() for k in labels):
123
+ ingress.setdefault("tls", [{
124
+ "hosts": [host or "example.local"],
125
+ "secretName": f"{host or 'example'}-tls"
126
+ }])
127
+
128
+ if ingress:
129
+ ingress.setdefault("annotations", {
130
+ "kubernetes.io/ingress.class": "nginx"
131
+ })
132
+
133
+ return ingress
134
+
135
+ # -------------------------------
136
+ # Chart generation
137
+ # -------------------------------
138
+
139
+ def generate_helm_chart(compose_path, output_dir, secret_provider, store_scope, reuse_store):
140
+ with open(compose_path) as f:
141
+ compose = yaml.safe_load(f)
142
+
143
+ output_dir.mkdir(parents=True, exist_ok=True)
144
+ templates_dir = output_dir / "templates"
145
+ templates_dir.mkdir(exist_ok=True)
146
+
147
+ # Chart.yaml
148
+ chart_yaml = {
149
+ "apiVersion": "v2",
150
+ "name": output_dir.name,
151
+ "version": "0.1.0",
152
+ "appVersion": "1.0.0",
153
+ "description": f"Helm chart auto-generated from {compose_path.name}"
154
+ }
155
+
156
+ # Build values.yaml
157
+ values = {"services": {}, "secretProvider": secret_provider}
158
+
159
+ for name, svc in compose.get("services", {}).items():
160
+ image = svc.get("image", "unknown")
161
+ env_raw = svc.get("environment", {})
162
+ env = {}
163
+ if isinstance(env_raw, list):
164
+ for item in env_raw:
165
+ k, v = item.split("=", 1) if "=" in item else (item, "")
166
+ env[k] = v
167
+ else:
168
+ env = env_raw
169
+
170
+ normal_env, sensitive_env = detect_sensitive_env(env)
171
+
172
+ service_data = {
173
+ "image": image,
174
+ "env": normal_env,
175
+ "secrets": sensitive_env,
176
+ }
177
+
178
+ # Database detection → StatefulSet + storage
179
+ if is_database(image):
180
+ service_data["storage"] = True
181
+ service_data["storageSize"] = DEFAULT_STORAGE_SIZES.get(
182
+ next((db for db in DEFAULT_STORAGE_SIZES if db in image.lower()), "postgres"),
183
+ "5Gi"
184
+ )
185
+
186
+ # Ports
187
+ ports = []
188
+ for p in svc.get("ports", []):
189
+ if isinstance(p, str):
190
+ parts = p.split(":")
191
+ port_map = {"containerPort": int(parts[-1])}
192
+ if len(parts) > 1 and parts[0].isdigit():
193
+ port_map["published"] = int(parts[0])
194
+ ports.append(port_map)
195
+ elif isinstance(p, dict):
196
+ ports.append(p)
197
+ if ports:
198
+ service_data["ports"] = ports
199
+
200
+ # Volumes
201
+ if "volumes" in svc:
202
+ service_data["storage"] = True
203
+
204
+ # Ingress
205
+ ingress = detect_ingress(svc)
206
+ if ingress:
207
+ service_data["ingress"] = ingress
208
+
209
+ values["services"][name] = service_data
210
+
211
+ # Save Chart.yaml and values.yaml
212
+ with open(output_dir / "Chart.yaml", "w") as f:
213
+ yaml.safe_dump(chart_yaml, f, sort_keys=False)
214
+ with open(output_dir / "values.yaml", "w") as f:
215
+ yaml.safe_dump(values, f, sort_keys=False)
216
+
217
+ # Copy templates
218
+ local_tpl_dir = Path(TEMPLATE_DIR)
219
+ for tpl in BASE_HELM_TEMPLATES:
220
+ src = local_tpl_dir / tpl
221
+ dest = templates_dir / tpl
222
+ if not src.exists():
223
+ print(f"⚠️ Missing template: {src}")
224
+ continue
225
+ copyfile(src, dest)
226
+
227
+ print(f"✅ Helm chart generated at {output_dir.resolve()}")
228
+
229
+ # -------------------------------
230
+ # CLI entry point
231
+ # -------------------------------
232
+
233
+ def main():
234
+ parser = argparse.ArgumentParser(description="Generate a Helm chart from Docker Compose")
235
+ parser.add_argument("compose_file", help="Path to docker-compose.yml")
236
+ parser.add_argument("--output", "-o", default="./generated-chart", help="Output directory")
237
+ parser.add_argument("--secret-provider", "-s", choices=["internal", "externalsecret"],
238
+ default="internal", help="Secret provider")
239
+ parser.add_argument("--store-scope", choices=["namespace", "cluster"],
240
+ default="namespace", help="SecretStore scope")
241
+ parser.add_argument("--reuse-store", default=None,
242
+ help="Reuse an existing SecretStore or ClusterSecretStore")
243
+ args = parser.parse_args()
244
+
245
+ compose_file = Path(args.compose_file)
246
+ if not compose_file.exists():
247
+ sys.exit(f"File not found: {compose_file}")
248
+
249
+ generate_helm_chart(
250
+ compose_path=compose_file,
251
+ output_dir=Path(args.output),
252
+ secret_provider=args.secret_provider,
253
+ store_scope=args.store_scope,
254
+ reuse_store=args.reuse_store,
255
+ )
256
+
257
+ if __name__ == "__main__":
258
+ main()
@@ -0,0 +1,47 @@
1
+ {{- range $name, $svc := .Values.services }}
2
+ apiVersion: apps/v1
3
+ kind: Deployment
4
+ metadata:
5
+ name: {{ $.Release.Name }}-{{ $name }}
6
+ spec:
7
+ replicas: 1
8
+ selector:
9
+ matchLabels:
10
+ app: {{ $.Release.Name }}-{{ $name }}
11
+ template:
12
+ metadata:
13
+ labels:
14
+ app: {{ $.Release.Name }}-{{ $name }}
15
+ spec:
16
+ containers:
17
+ - name: {{ $name }}
18
+ image: {{ $svc.image }}
19
+ env:
20
+ {{- range $k, $v := $svc.env }}
21
+ - name: {{ $k }}
22
+ value: {{ $v | quote }}
23
+ {{- end }}
24
+ {{- range $k, $v := $svc.secrets }}
25
+ - name: {{ $k }}
26
+ valueFrom:
27
+ secretKeyRef:
28
+ name: {{ $.Release.Name }}-{{ $name }}-secret
29
+ key: {{ $k }}
30
+ {{- end }}
31
+ ports:
32
+ {{- range $svc.ports }}
33
+ - containerPort: {{ .containerPort }}
34
+ {{- end }}
35
+ volumeMounts:
36
+ {{- if $svc.storage }}
37
+ - name: data
38
+ mountPath: /data
39
+ {{- end }}
40
+ volumes:
41
+ {{- if $svc.storage }}
42
+ - name: data
43
+ persistentVolumeClaim:
44
+ claimName: {{ $.Release.Name }}-{{ $name }}-pvc
45
+ {{- end }}
46
+ ---
47
+ {{- end }}
@@ -0,0 +1,27 @@
1
+ {{- range $name, $svc := .Values.services }}
2
+ {{- if and (eq $.Values.secretProvider "externalsecret") ($svc.secrets) }}
3
+ apiVersion: external-secrets.io/v1beta1
4
+ kind: ExternalSecret
5
+ metadata:
6
+ name: {{ $.Release.Name }}-{{ $name }}-externalsecret
7
+ spec:
8
+ refreshInterval: 1h
9
+ secretStoreRef:
10
+ {{- if $.Values.reuseStore }}
11
+ name: {{ $.Values.reuseStore }}
12
+ kind: {{ ternary "ClusterSecretStore" "SecretStore" (eq $.Values.storeScope "cluster") }}
13
+ {{- else }}
14
+ name: {{ $.Release.Name }}-secretstore
15
+ kind: {{ ternary "ClusterSecretStore" "SecretStore" (eq $.Values.storeScope "cluster") }}
16
+ {{- end }}
17
+ target:
18
+ name: {{ $.Release.Name }}-{{ $name }}-secret
19
+ data:
20
+ {{- range $k, $v := $svc.secrets }}
21
+ - secretKey: {{ $k }}
22
+ remoteRef:
23
+ key: {{ printf "%s/%s" $name $k | lower }}
24
+ {{- end }}
25
+ ---
26
+ {{- end }}
27
+ {{- end }}
@@ -0,0 +1,37 @@
1
+ {{- range $name, $svc := .Values.services }}
2
+ {{- if $svc.ingress }}
3
+ apiVersion: networking.k8s.io/v1
4
+ kind: Ingress
5
+ metadata:
6
+ name: {{ $.Release.Name }}-{{ $name }}-ingress
7
+ annotations:
8
+ {{- range $key, $val := $svc.ingress.annotations }}
9
+ {{ $key }}: {{ $val | quote }}
10
+ {{- end }}
11
+ spec:
12
+ rules:
13
+ {{- range $rule := $svc.ingress.rules }}
14
+ - host: {{ $rule.host }}
15
+ http:
16
+ paths:
17
+ - path: {{ $rule.path | default "/" }}
18
+ pathType: Prefix
19
+ backend:
20
+ service:
21
+ name: {{ $.Release.Name }}-{{ $name }}
22
+ port:
23
+ number: {{ $rule.port | default 80 }}
24
+ {{- end }}
25
+ {{- if $svc.ingress.tls }}
26
+ tls:
27
+ {{- range $tls := $svc.ingress.tls }}
28
+ - hosts:
29
+ {{- range $tls.hosts }}
30
+ - {{ . }}
31
+ {{- end }}
32
+ secretName: {{ $tls.secretName }}
33
+ {{- end }}
34
+ {{- end }}
35
+ ---
36
+ {{- end }}
37
+ {{- end }}
@@ -0,0 +1,15 @@
1
+ {{- range $name, $svc := .Values.services }}
2
+ {{- if $svc.storage }}
3
+ apiVersion: v1
4
+ kind: PersistentVolumeClaim
5
+ metadata:
6
+ name: {{ $.Release.Name }}-{{ $name }}-pvc
7
+ spec:
8
+ accessModes:
9
+ - ReadWriteOnce
10
+ resources:
11
+ requests:
12
+ storage: {{ $svc.storageSize | default "1Gi" }}
13
+ ---
14
+ {{- end }}
15
+ {{- end }}
@@ -0,0 +1,14 @@
1
+ {{- range $name, $svc := .Values.services }}
2
+ {{- if and (eq $.Values.secretProvider "internal") ($svc.secrets) }}
3
+ apiVersion: v1
4
+ kind: Secret
5
+ metadata:
6
+ name: {{ $.Release.Name }}-{{ $name }}-secret
7
+ type: Opaque
8
+ stringData:
9
+ {{- range $k, $v := $svc.secrets }}
10
+ {{ $k }}: {{ $v | quote }}
11
+ {{- end }}
12
+ ---
13
+ {{- end }}
14
+ {{- end }}
@@ -0,0 +1,16 @@
1
+ {{- if and (eq $.Values.secretProvider "externalsecret") (not $.Values.reuseStore) }}
2
+ apiVersion: external-secrets.io/v1beta1
3
+ kind: {{ ternary "ClusterSecretStore" "SecretStore" (eq $.Values.storeScope "cluster") }}
4
+ metadata:
5
+ name: {{ $.Release.Name }}-secretstore
6
+ spec:
7
+ provider:
8
+ vault:
9
+ server: "https://vault.example.com"
10
+ path: "secret/"
11
+ version: "v2"
12
+ auth:
13
+ tokenSecretRef:
14
+ name: "vault-auth"
15
+ key: "token"
16
+ {{- end }}
@@ -0,0 +1,18 @@
1
+ {{- range $name, $svc := .Values.services }}
2
+ apiVersion: v1
3
+ kind: Service
4
+ metadata:
5
+ name: {{ $.Release.Name }}-{{ $name }}
6
+ spec:
7
+ selector:
8
+ app: {{ $.Release.Name }}-{{ $name }}
9
+ ports:
10
+ {{- range $svc.ports }}
11
+ - port: {{ .published | default .target | default .containerPort }}
12
+ targetPort: {{ .target | default .containerPort }}
13
+ protocol: {{ .protocol | default "TCP" }}
14
+ name: {{ $name }}-{{ .containerPort }}
15
+ {{- end }}
16
+ type: {{ $svc.serviceType | default "ClusterIP" }}
17
+ ---
18
+ {{- end }}
@@ -0,0 +1,273 @@
1
+ Metadata-Version: 2.4
2
+ Name: helmgen
3
+ Version: 0.1.0
4
+ Summary: Auto-generate Helm charts from Docker Compose files
5
+ Author-email: Marcelo Garcia <marcelo.garcia@linux.com>
6
+ License: MIT
7
+ Project-URL: homepage, https://github.com/marcelodevops/helmgen
8
+ Project-URL: repository, https://github.com/marcelodevops/helmgen
9
+ Project-URL: issues, https://github.com/marcelodevops/helmgen/issues
10
+ Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: PyYAML>=6.0.2
14
+ Requires-Dist: ruamel.yaml>=0.18.6
15
+ Requires-Dist: jinja2>=3.1.4
16
+ Requires-Dist: click>=8.1.7
17
+ Requires-Dist: rich>=13.7.1
18
+ Dynamic: license-file
19
+
20
+ ## Helmgen
21
+ Auto-generate Helm charts from Docker Compose files.
22
+
23
+ **HelmGen** is a Python CLI tool that automatically converts your `docker-compose.yml` into a fully structured Helm chart — including Deployments, Services, PVCs, Ingress, and Secrets (internal or ExternalSecrets).
24
+ ##### Features:
25
+ - Convert **Docker Compose** files directly into **Helm charts**
26
+ - Auto-detect **databases** → generate StatefulSets + PVCs
27
+ - Auto-generate **Kubernetes Secrets** or **ExternalSecrets**
28
+ - Support for **Vault**, **AWS Secrets Manager**, or **ExternalSecrets Operator**
29
+ - Generate **SecretStore** or **ClusterSecretStore** automatically
30
+ - Auto-generate **Ingress** resources for web services
31
+ - Replace hardcoded secrets with safe placeholders in `values.yaml`
32
+ - Detect whether secrets should be env vars or mounted files
33
+ - CLI support for flexible options and overrides
34
+
35
+ ### Installation
36
+
37
+ ##### From source (recommended for development)
38
+ ```bash
39
+ git clone https://github.com/yourusername/helmgen.git
40
+ cd helmgen
41
+ pip install -e .
42
+ ```
43
+ - Then you can run it as a command:
44
+ ```bash
45
+ helmgen --help
46
+ ```
47
+
48
+ ### Usage
49
+ ```bash
50
+ helmgen docker-compose.yml [options]
51
+ ```
52
+ ### Example
53
+ ```bash
54
+ helmgen docker-compose.yml \
55
+ --output ./charts/myapp \
56
+ --secret-provider externalsecret \
57
+ --store-scope cluster \
58
+ --reuse-store global-vault-store
59
+ ```
60
+
61
+
62
+ - This generates
63
+ ```bash
64
+ charts/myapp/
65
+ ├── Chart.yaml
66
+ ├── values.yaml
67
+ └── templates/
68
+ ├── deployment.yaml
69
+ ├── service.yaml
70
+ ├── pvc.yaml
71
+ ├── ingress.yaml
72
+ ├── secrets.yaml
73
+ ├── externalsecret.yaml
74
+ └── secretstore.yaml
75
+
76
+ ```
77
+ - Then you can deploy
78
+ ```bash
79
+ helm install myapp ./charts/myapp
80
+ ```
81
+ ### CLI options
82
+
83
+ | Option | Description | Default |
84
+ | ----------------------- | ----------------------------------------------- | ------------------- |
85
+ | `--output, -o` | Directory for generated Helm chart | `./generated-chart` |
86
+ | `--secret-provider, -s` | `internal` (Helm Secret) or `externalsecret` | `internal` |
87
+ | `--store-scope` | `namespace` or `cluster` SecretStore | `namespace` |
88
+ | `--reuse-store` | Name of existing SecretStore/ClusterSecretStore | *None* |
89
+
90
+ ### Example
91
+
92
+ ```yaml
93
+ version: "3.8"
94
+ services:
95
+ web:
96
+ image: nginx:alpine
97
+ ports:
98
+ - "8080:80"
99
+ environment:
100
+ APP_ENV: production
101
+ SECRET_KEY: supersecret
102
+
103
+ db:
104
+ image: postgres:14
105
+ environment:
106
+ POSTGRES_USER: user
107
+ POSTGRES_PASSWORD: pass123
108
+ volumes:
109
+ - db-data:/var/lib/postgresql/data
110
+ ports:
111
+ - "5432:5432"
112
+
113
+ volumes:
114
+ db-data:
115
+
116
+ ```
117
+
118
+ - This will generate a Helm Chart with
119
+
120
+ - StatefulSet for Postgres
121
+ - Deployment for web
122
+ - Secrets/ExternalSecrets for passwords
123
+ - PVC for db-data
124
+ - Ingress if ports are exposed
125
+
126
+
127
+ - In this example the sensitive data is hard coded in the compose file with is a very bad practice but it's being used only for purpose of the example demonstration
128
+
129
+
130
+ ##### Secret management
131
+ - There are 2 options
132
+ 1. Internal (default helm secret)
133
+ 2. External
134
+
135
+ ##### if you want to run it as a python script (not recommended)
136
+
137
+ ```bash
138
+ python3 generator.py docker-compose.yml \
139
+ --output ./charts/myapp \
140
+ --secret-provider externalsecret \
141
+ --store-scope cluster \
142
+ --reuse-store global-vault-store
143
+ ```
144
+
145
+ ##### This will create a complete Helm chart with:
146
+
147
+ ```bash
148
+ charts/myapp/
149
+ ├── Chart.yaml
150
+ ├── values.yaml
151
+ └── templates/
152
+ ├── deployment.yaml
153
+ ├── service.yaml
154
+ ├── pvc.yaml
155
+ ├── ingress.yaml
156
+ ├── secrets.yaml
157
+ ├── externalsecret.yaml
158
+ └── secretstore.yaml
159
+
160
+ ```
161
+
162
+ ##### Templates
163
+
164
+ ```bash
165
+ helm_templates/
166
+ ├── deployment.yaml
167
+ ├── service.yaml
168
+ ├── pvc.yaml
169
+ ├── ingress.yaml
170
+ ├── secrets.yaml
171
+ ├── externalsecret.yaml
172
+ └── secretstore.yaml
173
+
174
+ ```
175
+
176
+ ##### Summary
177
+
178
+ Files and templates directory:
179
+ - generator.py → generates chart structure and populates values.yaml.
180
+ - helm_templates/ → reusable Jinja-style templates compatible with Helm.
181
+ - Seamless handling of:
182
+
183
+ - Secrets and ExternalSecrets
184
+ - Databases as StatefulSets (via PVC)
185
+ - Ingress auto-detection
186
+ - ClusterSecretStore / SecretStore support
187
+
188
+ ##### Run this version
189
+ - Generate files and templates from compose file:
190
+
191
+ ```bash
192
+ python3 generator.py docker-compose.yml --output ./charts/myapp --secret-provider externalsecret
193
+ ```
194
+
195
+ - Then install chart:
196
+ ```bash
197
+ helm install myapp ./charts/myapp
198
+
199
+ ```
200
+
201
+ ##### Dependencies
202
+
203
+ | Package | Purpose |
204
+ | --------------- | ----------------------------------------------------------------------------------------------------- |
205
+ | **PyYAML** | Primary YAML parser for reading `docker-compose.yml`. |
206
+ | **ruamel.yaml** | More advanced YAML manipulation (preserves comments, ordering). |
207
+ | **jinja2** | Template rendering for Helm YAML files (used when writing `templates/`). |
208
+ | **click** | Optional CLI framework (if you upgrade from `argparse` later for nicer commands). |
209
+ | **rich** | Optional but recommended — adds colored console output, status spinners, and better error formatting. |
210
+
211
+
212
+ ##### Install dependencies
213
+ ```bash
214
+ pip install -r requirements.txt
215
+ ```
216
+
217
+ ##### Update to run it as a CLI tool
218
+ - Usage
219
+
220
+ ```bash
221
+ helmgen docker-compose.yml --output ./charts/myapp
222
+
223
+ ```
224
+
225
+ ##### How it works
226
+
227
+ - project.scripts exposes a command called helmgen
228
+ - That command runs the main() function inside your generator.py
229
+ - Everything else is metadata (version, author, URLs, etc.)
230
+ - Dependencies match the ones from your requirements.txt
231
+
232
+
233
+ ##### Project layout
234
+
235
+ ```bash
236
+
237
+ helmgen/
238
+ ├── generator.py
239
+ ├── pyproject.toml
240
+ ├── README.md
241
+ ├── requirements.txt
242
+ └── helm_templates/
243
+ ├── deployment.yaml
244
+ ├── service.yaml
245
+ ├── pvc.yaml
246
+ ├── ingress.yaml
247
+ ├── secrets.yaml
248
+ ├── externalsecret.yaml
249
+ └── secretstore.yaml
250
+ ```
251
+ ##### Install locally for development
252
+ - From the folder containing pyproject.toml:
253
+ ```bash
254
+ pip install -e .
255
+ ```
256
+ ##### Then you can run it directly:
257
+ ```bash
258
+ helmgen docker-compose.yml --output ./charts/myapp
259
+ ```
260
+
261
+
262
+ ##### Build a distributable package
263
+ - to share it or publish it to PyPI (optional):
264
+ ```bash
265
+ python -m build
266
+ ```
267
+ - and it generates
268
+ ```bash
269
+ dist/
270
+ ├── helmgen-0.1.0-py3-none-any.whl
271
+ └── helmgen-0.1.0.tar.gz
272
+
273
+ ```
@@ -0,0 +1,16 @@
1
+ helmgen/__init__.py,sha256=c2DMioUcGc5wJcl4XrCTpvELYAmbMpM7jsalE5kRUL8,342
2
+ helmgen/__main__.py,sha256=mUYc0wTMCJmtUkqRd2o9yn__5Etcz8-_ESk7lHdJbLc,120
3
+ helmgen/generator.py,sha256=Dz-1jQ586jw-gn8FloduOqnLoVi5RlKLbcE1ac_90ec,8000
4
+ helmgen/helm_templates/deployment.yaml,sha256=2fs9P16lsl-cssJwlbiiX-HpGwdXAYnYIfJgEcrPkRU,1260
5
+ helmgen/helm_templates/externalsecret.yaml,sha256=v0uMlo-E6gUHq2YykELWdOtI5eDwvmoDqAXqT6yjPto,868
6
+ helmgen/helm_templates/ingress.yaml,sha256=hjE-NMEBZbhTBUQ1muGoVzKVH2FEXKBsRa9-RfJdMgE,935
7
+ helmgen/helm_templates/pvc.yaml,sha256=kup-GKJVvW8qsZwU6-aWVSPMfRNyCD1f17rVbH1MR7o,314
8
+ helmgen/helm_templates/secrets.yaml,sha256=NHlyBmQQQLNn-k54gq6xEjpNWZ9oN8Tojv0TMNhBu4M,331
9
+ helmgen/helm_templates/secretstore.yaml,sha256=Krt5EwHTcwk6jfqisdxbqCzG5TitFgn5TQ6ECx-C8YI,479
10
+ helmgen/helm_templates/service.yaml,sha256=jDsskT3cgDp6AQdKgf80RU40dxJzctAFrFg-i97jWIk,527
11
+ helmgen-0.1.0.dist-info/licenses/LICENSE,sha256=ROTPTYx7JJRaA9YLznUjB7n3do98U_pe1HPNkpnzVsQ,1070
12
+ helmgen-0.1.0.dist-info/METADATA,sha256=tZxCYnjD4gl__k1UnEKHeG85dGCCF4SvBEAeN27xg6M,7393
13
+ helmgen-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
+ helmgen-0.1.0.dist-info/entry_points.txt,sha256=Uz_e7M1qrMHd94bOH0WBxry40bPMYo5U9_FmJ0rSFe0,51
15
+ helmgen-0.1.0.dist-info/top_level.txt,sha256=j25JUIA8vxmXm5W6R2eY1dROuNb-n7a5A_Obl4FednE,8
16
+ helmgen-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ helmgen = helmgen.generator:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 marcelodevops
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ helmgen