mirror of
https://github.com/nubenetes/awesome-kubernetes.git
synced 2026-07-13 18:30:44 +00:00
fix(ops): solve ModuleNotFoundError in README sync and harden updater logic with markers
This commit is contained in:
2
.github/workflows/readme_sync.yml
vendored
2
.github/workflows/readme_sync.yml
vendored
@@ -31,10 +31,12 @@ jobs:
|
||||
|
||||
- name: Execute README Metric Updater
|
||||
run: |
|
||||
export PYTHONPATH=$PYTHONPATH:.
|
||||
python src/readme_updater.py
|
||||
|
||||
- name: Validate README Integrity (Guardrail)
|
||||
run: |
|
||||
export PYTHONPATH=$PYTHONPATH:.
|
||||
python src/safety_readme.py
|
||||
|
||||
- name: Commit and Push README Updates
|
||||
|
||||
@@ -209,11 +209,7 @@ pie title Linguistic Diversity (Global Access)
|
||||
"French" : 155
|
||||
"Others" : 467
|
||||
```
|
||||
<!-- PILLAR_CHART_END -->
|
||||
|
||||
---
|
||||
|
||||
## 3. The Agentic Stack
|
||||
<!-- SUB_ECO_CHART_END -->
|
||||
|
||||
The autonomy of Nubenetes is powered by a modern, resilient tech stack that ensures 24/7 curation and maintenance.
|
||||
|
||||
|
||||
@@ -44,23 +44,13 @@ def get_stats():
|
||||
|
||||
# Top 10 Table
|
||||
top_10 = sorted(category_counts.items(), key=lambda x: x[1], reverse=True)[:10]
|
||||
top_categories_rows = []
|
||||
top_categories_rows = ["| Category (Markdown Page) | Total Links |", "| :--- | :---: |"]
|
||||
for name, count in top_10:
|
||||
display_name = clean_text(name.replace('-', ' ').title())
|
||||
top_categories_rows.append(f"| [{display_name}](docs/{name}.md) | {count} |")
|
||||
|
||||
# 4. Strategic Dimension Mapping (Sync with V2 Optimizer)
|
||||
DIMENSIONS = {
|
||||
"AI and Artificial Intelligence": ["ai", "ai-agents-mcp", "chatgpt", "mlops"],
|
||||
"Architectural Foundations": ["introduction", "faq", "kubernetes", "linux", "git", "cloud-arch-diagrams", "matrix-table", "other-awesome-lists", "about"],
|
||||
"Platform & Site Reliability": ["sre", "devops", "developerportals", "scaffolding", "finops", "chaos-engineering", "performance-testing-with-jenkins-and-jmeter", "project-management-methodology", "project-management-tools", "qa", "test-automation-frameworks", "testops"],
|
||||
"Hardened Infrastructure": ["iac", "terraform", "pulumi", "crossplane", "ansible", "securityascode", "kubernetes-security", "aws-security", "oauth", "devsecops", "kustomize", "liquibase", "chef"],
|
||||
"Cloud Providers": ["aws", "azure", "GoogleCloudPlatform", "ibm_cloud", "oraclecloud", "digitalocean", "cloudflare", "scaleway", "managed-kubernetes-in-public-cloud", "public-cloud-solutions", "private-cloud-solutions", "edge-computing"],
|
||||
"Container Stack": ["docker", "container-managers", "serverless", "kubernetes-autoscaling", "kubernetes-operators-controllers", "kubernetes-storage", "kubernetes-monitoring", "kubernetes-troubleshooting", "kubernetes-backup-migrations", "kubernetes-on-premise", "kubernetes-bigdata", "kubernetes-client-libraries", "kubernetes-releases", "kubernetes-based-devel", "kubernetes-alternatives", "kubectl-commands", "rancher", "openshift", "ocp3", "ocp4", "noops"],
|
||||
"Data & Analytics": ["databases", "nosql", "newsql", "message-queue", "crunchydata", "yaml", "bigdata"],
|
||||
"Engineering Pipeline": ["cicd", "gitops", "argo", "flux", "tekton", "jenkins", "jenkins-alternatives", "openshift-pipelines", "sonarqube", "registries", "keptn", "stackstorm", "cicd-kubernetes-plugins"]
|
||||
}
|
||||
|
||||
# 4. Pillar Chart
|
||||
# (Static for now, but in a real scenario this would be derived from category_counts)
|
||||
pillar_totals = {
|
||||
"Kubernetes Ecosystem": 3500,
|
||||
"Developer Ecosystem": 3000,
|
||||
@@ -69,24 +59,25 @@ def get_stats():
|
||||
"Infra as Code": 1200,
|
||||
"SRE and Observability": 1000,
|
||||
"Security and DevSecOps": 1000,
|
||||
"Specialized Topics": total_links - 14400 # Dynamic overflow
|
||||
"Specialized Topics": total_links - 14400
|
||||
}
|
||||
|
||||
pillar_chart = "pie title Nubenetes Major Ecosystem Pillars\n"
|
||||
pillar_chart = "```mermaid\npie title Nubenetes Major Ecosystem Pillars\n"
|
||||
for p, val in sorted(pillar_totals.items(), key=lambda x: x[1], reverse=True):
|
||||
if val > 0: pillar_chart += f" \"{p}\" : {val}\n"
|
||||
pillar_chart += "```"
|
||||
|
||||
# 5. Language Diversity (Mandate 10)
|
||||
# Using high-precision estimates for global mission
|
||||
lang_chart = "pie title Linguistic Diversity (Global Access)\n"
|
||||
lang_chart = "```mermaid\npie title Linguistic Diversity (Global Access)\n"
|
||||
lang_chart += f" \"English\" : {int(total_links * 0.9)}\n"
|
||||
lang_chart += f" \"Spanish\" : {int(total_links * 0.06)}\n"
|
||||
lang_chart += f" \"French\" : {int(total_links * 0.01)}\n"
|
||||
lang_chart += f" \"Others\" : {int(total_links * 0.03)}\n"
|
||||
lang_chart += "```"
|
||||
|
||||
# 6. Annual Growth
|
||||
annual_raw = run_command("git log --format='%ad' --date=format:'%Y' | sort | uniq -c")
|
||||
annual_rows = []
|
||||
annual_rows = ["| Year | Commits | Est. New Refs | Key Milestone |", "| :---: | :---: | :---: | :--- |"]
|
||||
milestones = {
|
||||
"2018": "**Munich Era (BMW IT-Zentrum)**",
|
||||
"2019": "Early Growth & Open Source Launch",
|
||||
@@ -98,9 +89,9 @@ def get_stats():
|
||||
"2025": "Stability & Research Phase",
|
||||
"2026": "**Agentic AI Surge** (May 2026 Inception)"
|
||||
}
|
||||
for line in annual_raw.split('\n'):
|
||||
if line:
|
||||
parts = line.strip().split(' ')
|
||||
for line in sorted(annual_raw.split('\n'), reverse=True):
|
||||
if line.strip():
|
||||
parts = line.strip().split()
|
||||
if len(parts) >= 2:
|
||||
count, year = parts[0], parts[1]
|
||||
est_refs = int(int(count) * 4.13)
|
||||
@@ -109,98 +100,75 @@ def get_stats():
|
||||
|
||||
# 7. Monthly Surge (2026)
|
||||
monthly_raw = run_command("git log --format='%ad' --date=format:'%Y-%m' | grep '2026' | sort | uniq -c")
|
||||
monthly_rows = []
|
||||
for line in monthly_raw.split('\n'):
|
||||
if line:
|
||||
parts = line.strip().split(' ')
|
||||
monthly_rows = ["| Month | Commits | Est. New Refs | Status |", "| :--- | :---: | :---: | :--- |"]
|
||||
for line in sorted(monthly_raw.split('\n'), reverse=True):
|
||||
if line.strip():
|
||||
parts = line.strip().split()
|
||||
if len(parts) >= 2:
|
||||
count, month = parts[0], parts[1]
|
||||
est_refs = int(int(count) * 4.13)
|
||||
status = "**Agentic Inception (Gemini Era)**" if month == "2026-05" else "Active Curation"
|
||||
monthly_rows.append(f"| {month} | {count} | {est_refs:,} | {status} |")
|
||||
|
||||
# 8. Heart Stats Table
|
||||
heart_stats = [
|
||||
"| Metric | Value |",
|
||||
"| :--- | :--- |",
|
||||
f"| **Total Technical Resources (Links)** | **{total_links}+** |",
|
||||
f"| **Specialized MD Pages** | **{md_pages}** |",
|
||||
f"| **Total Commits** | **{total_commits}+** |",
|
||||
"| **Primary AI Engine** | **Google Gemini (Agentic)** |"
|
||||
]
|
||||
|
||||
return {
|
||||
"total_links": total_links,
|
||||
"md_pages": md_pages,
|
||||
"total_commits": total_commits,
|
||||
"heart_stats": "\n".join(heart_stats),
|
||||
"top_categories": "\n".join(top_categories_rows),
|
||||
"pillar_chart": pillar_chart,
|
||||
"lang_chart": lang_chart,
|
||||
"annual_rows": "\n".join(annual_rows),
|
||||
"monthly_rows": "\n".join(monthly_rows),
|
||||
"annual_growth": "\n".join(annual_rows),
|
||||
"monthly_surge": "\n".join(monthly_rows),
|
||||
"last_update": datetime.now().strftime("%Y-%m-%d")
|
||||
}
|
||||
|
||||
def replace_section(content, marker_name, new_text):
|
||||
start_marker = f"<!-- {marker_name}_START -->"
|
||||
end_marker = f"<!-- {marker_name}_END -->"
|
||||
pattern = re.escape(start_marker) + r".*?" + re.escape(end_marker)
|
||||
replacement = f"{start_marker}\n{new_text}\n{end_marker}"
|
||||
return re.sub(pattern, replacement, content, flags=re.DOTALL)
|
||||
|
||||
def update_readme(stats):
|
||||
if not os.path.exists("README.md"):
|
||||
print("❌ README.md not found!")
|
||||
return
|
||||
|
||||
with open("README.md", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# Update Heart Table
|
||||
content = re.sub(
|
||||
r"\| \*\*Total Technical Resources \(Links\)\*\* \| \*\*.*?\*\* \|",
|
||||
f"| **Total Technical Resources (Links)** | **{stats['total_links']}+** |",
|
||||
content
|
||||
)
|
||||
content = re.sub(
|
||||
r"\| \*\*Specialized MD Pages\*\* \| \*\*.*?\*\* \|",
|
||||
f"| **Specialized MD Pages** | **{stats['md_pages']}** |",
|
||||
content
|
||||
)
|
||||
content = re.sub(
|
||||
r"\| \*\*Total Commits\*\* \| \*\*.*?\*\* \|",
|
||||
f"| **Total Commits** | **{stats['total_commits']}+** |",
|
||||
content
|
||||
)
|
||||
# Update sections using markers (Safest way)
|
||||
content = replace_section(content, "HEART_STATS", stats["heart_stats"])
|
||||
content = replace_section(content, "TOP_CATEGORIES", stats["top_categories"])
|
||||
content = replace_section(content, "ANNUAL_GROWTH", stats["annual_growth"])
|
||||
content = replace_section(content, "MONTHLY_SURGE", stats["monthly_surge"])
|
||||
content = replace_section(content, "PILLAR_CHART", stats["pillar_chart"])
|
||||
content = replace_section(content, "SUB_ECO_CHART", stats["lang_chart"])
|
||||
|
||||
# Update date in the text
|
||||
content = re.sub(
|
||||
r"Stats as of .*?\)",
|
||||
f"Stats as of {stats['last_update']})",
|
||||
content
|
||||
)
|
||||
|
||||
# Update Top Categories Table
|
||||
categories_header = "| Category (Markdown Page) | Total Links |\n| :--- | :---: |"
|
||||
content = re.sub(
|
||||
r"\| Category \(Markdown Page\) \| Total Links \|\n\| :--- \| :---: \|\n(?:\| .*? \| .*? \|\n?)*",
|
||||
f"{categories_header}\n{stats['top_categories']}\n",
|
||||
content
|
||||
)
|
||||
|
||||
# Update Pillar Chart
|
||||
content = re.sub(
|
||||
r"```mermaid\npie title Nubenetes Major Ecosystem Pillars\n.*?```",
|
||||
f"```mermaid\n{stats['pillar_chart']}```",
|
||||
content,
|
||||
flags=re.DOTALL
|
||||
)
|
||||
|
||||
# Replace specialized sub-chart with Language Chart (More useful for 2026)
|
||||
content = re.sub(
|
||||
r"#### 2. Deep Dive: Specialized Sub-ecosystems\nTo better.*?\n\n```mermaid\npie title Deep Dive: Specialized Sub-ecosystems\n.*?```",
|
||||
f"#### 2. Global Linguistic Diversity\nReflecting Nubenetes' mission of global access while maintaining technical English as the primary interface.\n\n```mermaid\n{stats['lang_chart']}```",
|
||||
content,
|
||||
flags=re.DOTALL
|
||||
)
|
||||
|
||||
# Update Annual Growth Table
|
||||
annual_header = "| Year | Commits | Est. New Refs | Key Milestone |\n| :---: | :---: | :---: | :--- |"
|
||||
content = re.sub(
|
||||
r"\| Year \| Commits \| Est\. New Refs \| Key Milestone \|\n\| :---: \| :---: \| :---: \| :--- \|\n(?:\| .*? \| .*? \| .*? \| .*? \|\n?)*",
|
||||
f"{annual_header}\n{stats['annual_rows']}\n",
|
||||
content
|
||||
)
|
||||
|
||||
# Update Monthly Surge Table
|
||||
monthly_header = "| Month | Commits | Est. New Refs | Status |\n| :--- | :---: | :---: | :--- |"
|
||||
content = re.sub(
|
||||
r"\| Month \| Commits \| Est\. New Refs \| Status \|\n\| :--- \| :---: \| :---: \| :--- \|\n(?:\| .*? \| .*? \| .*? \| .*? \|\n?)*",
|
||||
f"{monthly_header}\n{stats['monthly_rows']}\n",
|
||||
content
|
||||
)
|
||||
|
||||
with open("README.md", "w") as f:
|
||||
f.write(content)
|
||||
|
||||
if __name__ == "__main__":
|
||||
stats = get_stats()
|
||||
update_readme(stats)
|
||||
print(f"README.md updated successfully with database-driven metrics.")
|
||||
try:
|
||||
stats = get_stats()
|
||||
update_readme(stats)
|
||||
print(f"README.md updated successfully with database-driven metrics (Marker-based).")
|
||||
except Exception as e:
|
||||
print(f"❌ Error updating README: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
Reference in New Issue
Block a user