Skip to content

Commit 00d092d

Browse files
authored
Merge pull request #14 from cloudengine-labs/copilot/add-process-first-section
fix: init wizard captures no selections — add Space instruction to checkbox prompts
2 parents 99e8914 + 54ba4e9 commit 00d092d

12 files changed

Lines changed: 628 additions & 68 deletions

.gitignore

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,108 @@
1+
# Python
12
__pycache__/
23
*.py[cod]
34
*.pyo
4-
.pytest_cache/
5-
*.egg-info/
5+
*.pyd
6+
*$py.class
7+
*.so
8+
.Python
9+
10+
# Virtual Environments
11+
.env
12+
.venv/
13+
venv/
14+
ENV/
15+
env/
16+
env.bak/
17+
venv.bak/
18+
19+
# Distribution / packaging
620
dist/
721
build/
8-
.env
22+
*.egg-info/
23+
*.egg
24+
.eggs/
25+
lib/
26+
lib64/
27+
parts/
28+
sdist/
29+
var/
30+
wheels/
31+
pip-wheel-metadata/
32+
share/python-wheels/
33+
*.manifest
34+
*.spec
35+
36+
# Installer logs
37+
pip-log.txt
38+
pip-delete-this-directory.txt
39+
40+
# Unit test / coverage reports
41+
htmlcov/
42+
.tox/
43+
.nox/
44+
.coverage
45+
.coverage.*
46+
.cache
47+
nosetests.xml
48+
coverage.xml
49+
*.cover
950
*.log
51+
.pytest_cache/
52+
.hypothesis/
53+
pytestdebug.log
54+
55+
# Jupyter Notebook
56+
.ipynb_checkpoints
57+
*.ipynb_checkpoints/
58+
59+
# PyCharm
60+
.idea/
61+
*.iml
62+
*.iws
63+
.idea_modules/
64+
65+
# VS Code
66+
.vscode/
67+
*.code-workspace
68+
69+
# Spyder
70+
.spyderproject
71+
.spyproject
72+
73+
# Rope
74+
.ropeproject
75+
76+
# mkdocs
77+
site/
78+
docs/_build/
79+
80+
# mypy
81+
.mypy_cache/
82+
.dmypy.json
83+
dmypy.json
84+
85+
# Pyre type checker
86+
.pyre/
87+
88+
# pytype static type analyzer
89+
.pytype/
90+
91+
# Cython debug symbols
92+
cython_debug/
93+
94+
# Jekyll
1095
_site/
1196
.jekyll-cache/
12-
.venv/
13-
venv/
14-
docs/test-report.html
1597

1698
# Hugo build artifacts
1799
hugo-docs/public/
18100
hugo-docs/resources/
19101
hugo-docs/.hugo_build.lock
20102

103+
# Test reports
104+
docs/test-report.html
105+
21106
# Scaffold-generated output files (created by `python -m cli.devopsos scaffold *`)
22107
.gitlab-ci.yml
23108
Jenkinsfile
-146 Bytes
Binary file not shown.
-8.36 KB
Binary file not shown.
-10.4 KB
Binary file not shown.
-32.4 KB
Binary file not shown.
-25.1 KB
Binary file not shown.
-2.26 KB
Binary file not shown.

cli/devopsos.py

Lines changed: 148 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ProcessFirstSection(str, enum.Enum):
2121
what = "what"
2222
mapping = "mapping"
2323
tips = "tips"
24+
best_practices = "best_practices"
2425
all = "all"
2526

2627

@@ -32,40 +33,126 @@ def init(
3233
):
3334
"""Interactive project initializer."""
3435
typer.echo("Welcome to DevOps-OS Init Wizard!")
36+
typer.echo("Tools are grouped by Process-First DevOps principles (Systems Thinking).\n")
37+
38+
# ── Canonical tool lists ──────────────────────────────────────────────
39+
ALL_LANGUAGES = ["python", "java", "node", "ruby", "csharp", "php", "rust",
40+
"typescript", "kotlin", "c", "cpp", "javascript", "go"]
41+
ALL_CICD = ["docker", "podman", "terraform", "kubectl", "helm", "github_actions", "jenkins"]
42+
ALL_KUBERNETES = ["k9s", "kustomize", "argocd_cli", "lens", "kubeseal",
43+
"flux", "kind", "minikube", "openshift_cli"]
44+
ALL_BUILD_TOOLS = ["gradle", "maven", "ant", "make", "cmake"]
45+
ALL_CODE_ANALYSIS = ["sonarqube", "checkstyle", "pmd", "eslint", "pylint"]
46+
ALL_DEVOPS_TOOLS = ["nexus", "prometheus", "grafana", "elk", "jenkins"]
3547

36-
categories = {
37-
"languages": ["python", "java", "node", "ruby", "csharp", "php", "rust", "typescript", "kotlin", "c", "cpp", "javascript", "go"],
38-
"cicd": ["docker", "terraform", "kubectl", "helm", "github_actions", "jenkins"],
39-
"kubernetes": ["k9s", "kustomize", "argocd_cli", "lens", "kubeseal", "flux", "kind", "minikube", "openshift_cli"],
40-
"build_tools": ["gradle", "maven", "ant", "make", "cmake"],
41-
"code_analysis": ["sonarqube", "checkstyle", "pmd", "eslint", "pylint"],
42-
"devops_tools": ["nexus", "prometheus", "grafana", "elk", "jenkins"]
43-
}
4448
versions_defaults = {
4549
"python": "3.11", "java": "17", "node": "20", "go": "1.21", "nexus": "3.50.0",
4650
"prometheus": "2.45.0", "grafana": "10.0.0", "k9s": "0.29.1", "argocd": "2.8.4",
4751
"flux": "2.1.2", "kustomize": "5.2.1", "jenkins": "2.440.1"
4852
}
49-
config = {}
50-
selected_versions = {}
51-
selected_options = {}
52-
for cat, opts in categories.items():
53-
selected = inquirer.checkbox(message=f"Select {cat.replace('_', ' ').title()}:", choices=opts).execute()
54-
selected_options[cat] = selected
55-
# Now build config with True/False for each option
56-
for cat, opts in categories.items():
57-
config[cat] = {opt: (opt in selected_options[cat]) for opt in opts}
58-
# Prompt for version only for selected
59-
if cat == "languages" or cat == "devops_tools":
60-
for opt in selected_options[cat]:
61-
if opt in versions_defaults:
62-
selected_versions[opt] = inquirer.text(message=f"{opt.title()} version:", default=versions_defaults[opt]).execute()
63-
if cat == "kubernetes":
64-
for opt in selected_options[cat]:
65-
if opt in ["k9s", "argocd_cli", "flux", "kustomize"]:
66-
vkey = opt if opt != "argocd_cli" else "argocd"
67-
selected_versions[vkey] = inquirer.text(message=f"{opt.title()} version:", default=versions_defaults.get(vkey, "")).execute()
68-
config["versions"] = selected_versions
53+
54+
# ── Wizard groups aligned with Process-First DevOps principles ────────
55+
# Each group maps to a DevOps stage in the Systems Thinking value stream.
56+
wizard_groups = {
57+
"Languages": {
58+
"choices": ALL_LANGUAGES,
59+
"description": "Programming languages for your project",
60+
},
61+
"Containerization [CONTAINER stage]": {
62+
"choices": ["docker", "podman"],
63+
"description": "Container runtimes to build, ship, and run application images",
64+
},
65+
"Build Tools [BUILD stage]": {
66+
"choices": ["gradle", "maven", "ant", "make", "cmake", "nexus"],
67+
"description": "Tools to compile, package, and store build artifacts",
68+
},
69+
"Test & Quality [TEST stage]": {
70+
"choices": ["sonarqube", "checkstyle", "pmd", "eslint", "pylint"],
71+
"description": "Static analysis and quality gates to enforce standards early",
72+
},
73+
"Kubernetes [KUBERNETES stage]": {
74+
"choices": ["kubectl", "helm", "kustomize", "k9s", "argocd_cli",
75+
"flux", "kind", "minikube", "lens", "kubeseal", "openshift_cli"],
76+
"description": "Kubernetes CLI tools, GitOps engines, and local cluster runtimes",
77+
},
78+
"CI/CD & Deploy [DEPLOY stage]": {
79+
"choices": ["github_actions", "jenkins", "terraform"],
80+
"description": "CI/CD pipelines, IaC provisioning, and deployment automation",
81+
},
82+
"SRE & Monitoring [SRE/MONITORING stage]": {
83+
"choices": ["prometheus", "grafana", "elk"],
84+
"description": "Observability stack: metrics, dashboards, and centralised logs",
85+
},
86+
}
87+
88+
selected_by_group: dict = {}
89+
selected_versions: dict = {}
90+
91+
for group_label, group_info in wizard_groups.items():
92+
typer.echo(f"\n 📌 {group_info['description']}")
93+
selected = inquirer.checkbox(
94+
message=f"Select {group_label}:",
95+
choices=group_info["choices"],
96+
instruction="(Space to select, ↑↓ to navigate, Enter to confirm)",
97+
).execute()
98+
selected_by_group[group_label] = selected
99+
100+
# ── Version prompts ───────────────────────────────────────────────────
101+
all_selected = {tool for tools in selected_by_group.values() for tool in tools}
102+
for tool in all_selected:
103+
vkey = "argocd" if tool == "argocd_cli" else tool
104+
if vkey in versions_defaults:
105+
selected_versions[vkey] = inquirer.text(
106+
message=f"{tool.title()} version:",
107+
default=versions_defaults[vkey],
108+
).execute()
109+
110+
# ── Map wizard selections back to legacy JSON structure ───────────────
111+
# Keep the devcontainer.env.json keys identical to scaffold_devcontainer
112+
# output for backward compatibility.
113+
def _sel(group): return selected_by_group.get(group, [])
114+
115+
container_sel = _sel("Containerization [CONTAINER stage]")
116+
build_sel = _sel("Build Tools [BUILD stage]")
117+
test_sel = _sel("Test & Quality [TEST stage]")
118+
k8s_sel = _sel("Kubernetes [KUBERNETES stage]")
119+
deploy_sel = _sel("CI/CD & Deploy [DEPLOY stage]")
120+
sre_sel = _sel("SRE & Monitoring [SRE/MONITORING stage]")
121+
lang_sel = _sel("Languages")
122+
123+
config = {
124+
"languages": {opt: opt in lang_sel for opt in ALL_LANGUAGES},
125+
"cicd": {
126+
"docker": "docker" in container_sel,
127+
"podman": "podman" in container_sel,
128+
"terraform": "terraform" in deploy_sel,
129+
"kubectl": "kubectl" in k8s_sel,
130+
"helm": "helm" in k8s_sel,
131+
"github_actions": "github_actions" in deploy_sel,
132+
"jenkins": "jenkins" in deploy_sel,
133+
},
134+
"kubernetes": {
135+
"k9s": "k9s" in k8s_sel,
136+
"kustomize": "kustomize" in k8s_sel,
137+
"argocd_cli": "argocd_cli" in k8s_sel,
138+
"lens": "lens" in k8s_sel,
139+
"kubeseal": "kubeseal" in k8s_sel,
140+
"flux": "flux" in k8s_sel,
141+
"kind": "kind" in k8s_sel,
142+
"minikube": "minikube" in k8s_sel,
143+
"openshift_cli": "openshift_cli" in k8s_sel,
144+
},
145+
"build_tools": {opt: opt in build_sel for opt in ALL_BUILD_TOOLS},
146+
"code_analysis": {opt: opt in test_sel for opt in ALL_CODE_ANALYSIS},
147+
"devops_tools": {
148+
"nexus": "nexus" in build_sel,
149+
"prometheus": "prometheus" in sre_sel,
150+
"grafana": "grafana" in sre_sel,
151+
"elk": "elk" in sre_sel,
152+
"jenkins": "jenkins" in deploy_sel,
153+
},
154+
"versions": selected_versions,
155+
}
69156

70157
# Review step: show config and confirm
71158
typer.echo("\nReview your configuration:")
@@ -88,39 +175,52 @@ def init(
88175
build_args = {}
89176
# Languages
90177
lang_map = {
91-
"python": "INSTALL_PYTHON", "java": "INSTALL_JAVA", "node": "INSTALL_JS", "ruby": "INSTALL_RUBY",
92-
"csharp": "INSTALL_CSHARP", "php": "INSTALL_PHP", "rust": "INSTALL_RUST", "typescript": "INSTALL_TYPESCRIPT",
93-
"kotlin": "INSTALL_KOTLIN", "c": "INSTALL_C", "cpp": "INSTALL_CPP", "javascript": "INSTALL_JAVASCRIPT", "go": "INSTALL_GO"
178+
"python": "INSTALL_PYTHON", "java": "INSTALL_JAVA", "node": "INSTALL_JS",
179+
"ruby": "INSTALL_RUBY", "csharp": "INSTALL_CSHARP", "php": "INSTALL_PHP",
180+
"rust": "INSTALL_RUST", "typescript": "INSTALL_TYPESCRIPT",
181+
"kotlin": "INSTALL_KOTLIN", "c": "INSTALL_C", "cpp": "INSTALL_CPP",
182+
"javascript": "INSTALL_JAVASCRIPT", "go": "INSTALL_GO"
94183
}
95184
for lang, arg in lang_map.items():
96185
build_args[arg] = str(config["languages"].get(lang, False)).lower()
97-
# CICD
186+
# CICD (includes container runtimes docker/podman)
98187
cicd_map = {
99-
"docker": "INSTALL_DOCKER", "terraform": "INSTALL_TERRAFORM", "kubectl": "INSTALL_KUBECTL", "helm": "INSTALL_HELM", "github_actions": "INSTALL_GITHUB_ACTIONS", "jenkins": "INSTALL_JENKINS"
188+
"docker": "INSTALL_DOCKER", "podman": "INSTALL_PODMAN",
189+
"terraform": "INSTALL_TERRAFORM",
190+
"kubectl": "INSTALL_KUBECTL", "helm": "INSTALL_HELM",
191+
"github_actions": "INSTALL_GITHUB_ACTIONS", "jenkins": "INSTALL_JENKINS"
100192
}
101193
for tool, arg in cicd_map.items():
102194
build_args[arg] = str(config["cicd"].get(tool, False)).lower()
103195
# Kubernetes
104196
k8s_map = {
105-
"k9s": "INSTALL_K9S", "kustomize": "INSTALL_KUSTOMIZE", "argocd_cli": "INSTALL_ARGOCD_CLI", "lens": "INSTALL_LENS", "kubeseal": "INSTALL_KUBESEAL", "flux": "INSTALL_FLUX", "kind": "INSTALL_KIND", "minikube": "INSTALL_MINIKUBE", "openshift_cli": "INSTALL_OPENSHIFT_CLI"
197+
"k9s": "INSTALL_K9S", "kustomize": "INSTALL_KUSTOMIZE",
198+
"argocd_cli": "INSTALL_ARGOCD_CLI", "lens": "INSTALL_LENS",
199+
"kubeseal": "INSTALL_KUBESEAL", "flux": "INSTALL_FLUX",
200+
"kind": "INSTALL_KIND", "minikube": "INSTALL_MINIKUBE",
201+
"openshift_cli": "INSTALL_OPENSHIFT_CLI"
106202
}
107203
for tool, arg in k8s_map.items():
108204
build_args[arg] = str(config["kubernetes"].get(tool, False)).lower()
109205
# Build tools
110206
build_map = {
111-
"gradle": "INSTALL_GRADLE", "maven": "INSTALL_MAVEN", "ant": "INSTALL_ANT", "make": "INSTALL_MAKE", "cmake": "INSTALL_CMAKE"
207+
"gradle": "INSTALL_GRADLE", "maven": "INSTALL_MAVEN", "ant": "INSTALL_ANT",
208+
"make": "INSTALL_MAKE", "cmake": "INSTALL_CMAKE"
112209
}
113210
for tool, arg in build_map.items():
114211
build_args[arg] = str(config["build_tools"].get(tool, False)).lower()
115212
# Code analysis
116213
analysis_map = {
117-
"sonarqube": "INSTALL_SONARQUBE", "checkstyle": "INSTALL_CHECKSTYLE", "pmd": "INSTALL_PMD", "eslint": "INSTALL_ESLINT", "pylint": "INSTALL_PYLINT"
214+
"sonarqube": "INSTALL_SONARQUBE", "checkstyle": "INSTALL_CHECKSTYLE",
215+
"pmd": "INSTALL_PMD", "eslint": "INSTALL_ESLINT", "pylint": "INSTALL_PYLINT"
118216
}
119217
for tool, arg in analysis_map.items():
120218
build_args[arg] = str(config["code_analysis"].get(tool, False)).lower()
121219
# DevOps tools
122220
devops_map = {
123-
"nexus": "INSTALL_NEXUS", "prometheus": "INSTALL_PROMETHEUS", "grafana": "INSTALL_GRAFANA", "elk": "INSTALL_ELK", "jenkins": "INSTALL_JENKINS"
221+
"nexus": "INSTALL_NEXUS", "prometheus": "INSTALL_PROMETHEUS",
222+
"grafana": "INSTALL_GRAFANA", "elk": "INSTALL_ELK",
223+
"jenkins": "INSTALL_JENKINS"
124224
}
125225
for tool, arg in devops_map.items():
126226
build_args[arg] = str(config["devops_tools"].get(tool, False)).lower()
@@ -181,10 +281,11 @@ def process_first_cmd(
181281
ProcessFirstSection.all,
182282
help=(
183283
"Section to display:\n\n"
184-
" 'what' — What Process-First is and its 5 core principles\n\n"
185-
" 'mapping' — How each principle maps to a devopsos scaffold command\n\n"
186-
" 'tips' — AI prompts and book recommendations for DevOps beginners\n\n"
187-
" 'all' — All sections combined (default)"
284+
" 'what' — What Process-First is, 5 core principles + thought leaders\n\n"
285+
" 'mapping' — How each principle maps to a devopsos scaffold command\n\n"
286+
" 'tips' — AI prompts and book recommendations for DevOps beginners\n\n"
287+
" 'best_practices' — Best practices by stage (build/test/iac/deploy/sre/monitoring/security)\n\n"
288+
" 'all' — All sections combined (default)"
188289
),
189290
show_choices=True,
190291
),
@@ -194,15 +295,16 @@ def process_first_cmd(
194295
\b
195296
Quick invocation guide:
196297
197-
python -m cli.devopsos process-first # full overview
198-
python -m cli.devopsos process-first --section what # core principles
199-
python -m cli.devopsos process-first --section mapping # tool mapping table
200-
python -m cli.devopsos process-first --section tips # AI prompts for beginners
298+
python -m cli.devopsos process-first # full overview
299+
python -m cli.devopsos process-first --section what # core principles + thought leaders
300+
python -m cli.devopsos process-first --section mapping # tool mapping table
301+
python -m cli.devopsos process-first --section tips # AI prompts for beginners
302+
python -m cli.devopsos process-first --section best_practices # best practices by stage
201303
202304
You can also run the module directly:
203305
204306
python -m cli.process_first
205-
python -m cli.process_first --section mapping
307+
python -m cli.process_first --section best_practices
206308
"""
207309
process_first.display(section.value)
208310

0 commit comments

Comments
 (0)