master
py 735 lines 27.9 KB
Raw
1 #!/usr/bin/env python3
2 import argparse
3 import json
4 import re
5 import shutil
6 import sys
7 from pathlib import Path
8
9 # Registry used to decide which README.md should symlink to which generated file
10 symlink_dict = {}
11
12 # Mapping of integration id → output file path (repo-relative), populated by write_to_file()
13 id_to_path = {}
14
15
16 # -----------------------------
17 # FS utilities
18 # -----------------------------
19 def cleanup(only_base_paths=None):
20 """
21 Clean generated /integrations folders.
22 - If only_base_paths is provided (list of base dirs), clean ONLY those.
23 - Otherwise, do a full cleanup (legacy behavior).
24 """
25 targets = [
26 "src/go/plugin/go.d/collector",
27 "src/go/plugin/scripts.d/collector",
28 "src/go/plugin/ibm.d/modules",
29 "src/crates/netdata-otel",
30 "src/crates/netflow-plugin",
31 "src/collectors",
32 "src/exporting",
33 "integrations/cloud-notifications",
34 "integrations/logs",
35 "integrations/cloud-authentication",
36 "src/go/plugin/agent/secrets/secretstore/backends",
37 "src/go/plugin/go.d/discovery/sdext/discoverer",
38 ]
39 bases = only_base_paths if only_base_paths else targets
40 for base in bases:
41 for p in Path(base).glob("**/integrations"):
42 shutil.rmtree(p, ignore_errors=True)
43
44
45 def clean_and_write(md: str, path: Path):
46 """
47 Convert custom markers to HTML/plain text for GitHub-rendered .md files.
48 relatedResource tags are left as-is here; they are resolved in a post-pass
49 once id_to_path is fully populated.
50 """
51 md = re.sub(r'\{% details open=true summary="(.*?)" %\}', r'<details open><summary>\1</summary>\n', md)
52 md = re.sub(r'\{% details summary="(.*?)" %\}', r'<details><summary>\1</summary>\n', md)
53 md = md.replace("{% /details %}", "</details>\n")
54 path.write_text(md, encoding="utf-8")
55
56
57 def resolve_related_links():
58 """
59 Post-process all written files: convert relatedResource tags to markdown links.
60 Must be called after all files are written and id_to_path is fully populated.
61 """
62 for fpath in id_to_path.values():
63 p = Path(fpath)
64 if not p.exists():
65 continue
66 md = p.read_text(encoding="utf-8")
67 if '{% relatedResource' not in md:
68 continue
69
70 def _resolve(m):
71 rid = m.group(1)
72 name = m.group(2)
73 target = id_to_path.get(rid)
74 if target:
75 return f'[{name}](/{target})'
76 return name
77
78 md = re.sub(r'\{% relatedResource id="([^"]*)" %\}(.*?)\{% /relatedResource %\}', _resolve, md)
79 p.write_text(md, encoding="utf-8")
80
81
82 def build_path(meta_yaml_link: str) -> str:
83 """
84 Convert GitHub edit link to local repo path (without trailing /metadata.yaml).
85 """
86 return (
87 meta_yaml_link.replace("https://github.com/netdata/", "")
88 .split("/", 1)[1]
89 .replace("edit/master/", "")
90 .replace("blob/master/", "")
91 .replace("/metadata.yaml", "")
92 )
93
94
95 # -----------------------------
96 # Content builders
97 # -----------------------------
98 def add_custom_edit_url(markdown_string: str, meta_yaml_link: str, sidebar_label_string: str,
99 mode: str = "default", output_slug: str = None) -> str:
100 """
101 Inject custom_edit_url into the metadata header.
102 """
103 slug = output_slug or clean_string(sidebar_label_string)
104
105 if mode == "default":
106 path_to_md_file = f"{meta_yaml_link.replace('/metadata.yaml', '')}/integrations/{slug}"
107 elif mode in ("cloud-notification", "logs", "cloud-authentication"):
108 path_to_md_file = meta_yaml_link.replace("metadata.yaml", f"integrations/{slug}")
109 elif mode == "agent-notification":
110 path_to_md_file = meta_yaml_link.replace("metadata.yaml", "README")
111 else:
112 # safe fallback
113 path_to_md_file = f"{meta_yaml_link.replace('/metadata.yaml', '')}/integrations/{slug}"
114
115 return markdown_string.replace(
116 "<!--startmeta", f"<!--startmeta\ncustom_edit_url: \"{path_to_md_file}.md\""
117 )
118
119
120 def clean_string(string: str) -> str:
121 return (
122 string.lower()
123 .replace(" ", "_")
124 .replace("/", "-")
125 .replace("(", "")
126 .replace(")", "")
127 .replace(":", "")
128 )
129
130
131 def read_integrations_js(path_to_file: str):
132 """
133 Parse integrations/integrations.js and return (categories, integrations).
134 """
135 try:
136 data = Path(path_to_file).read_text()
137 categories_str = data.split("export const categories = ")[1].split("export const integrations = ")[0]
138 integrations_str = data.split("export const categories = ")[1].split("export const integrations = ")[1]
139 return json.loads(categories_str), json.loads(integrations_str)
140 except FileNotFoundError as e:
141 print("Exception", e)
142 return [], []
143
144
145 def generate_category_from_name(category_fragment, category_array) -> str:
146 """
147 Given a split category id (by ".") and categories tree, return Learn path.
148 """
149 category_name = ""
150 i = 0
151 dummy_id = category_fragment[0]
152
153 while i < len(category_fragment):
154 for category in category_array:
155 if dummy_id == category["id"]:
156 category_name += f"/{category['name']}"
157 try:
158 dummy_id = f"{dummy_id}.{category_fragment[i + 1]}"
159 except IndexError:
160 return category_name.split("/", 1)[1]
161 category_array = category["children"]
162 break
163 i += 1
164 return category_name.split("/", 1)[1] if category_name else ""
165
166
167 def create_overview(integration, filename: str, overview_key_name: str = "overview") -> str:
168 # Empty overview_key_name => only image on overview
169 if not overview_key_name:
170 return f"# {integration['meta']['name']}\n\n<img src=\"https://netdata.cloud/img/{filename}\" width=\"150\"/>\n"
171
172 split = re.split(r"(#.*\n)", integration[overview_key_name], maxsplit=1)
173 first_overview_part = split[1]
174 rest_overview_part = split[2]
175
176 if not filename:
177 return f"{first_overview_part}{rest_overview_part}"
178
179 return f"""{first_overview_part}
180
181 <img src="https://netdata.cloud/img/{filename}" width="150"/>
182
183 {rest_overview_part}"""
184
185
186 def build_readme_from_integration(integration, categories, mode: str = ""):
187 """
188 Build the README markdown string for an integration.
189 Returns (meta_yaml, sidebar_label, learn_rel_path, md, community_badge)
190 """
191 md = ""
192 meta_yaml = ""
193 sidebar_label = ""
194 learn_rel_path = ""
195
196 try:
197 if mode == "collector":
198 meta_yaml = integration["edit_link"].replace("blob", "edit")
199 sidebar_label = integration["meta"]["monitored_instance"]["name"]
200 learn_rel_path = generate_category_from_name(
201 integration["meta"]["monitored_instance"]["categories"][0].split("."), categories
202 ).replace("Data Collection", "Collecting Metrics/Collectors")
203 keywords = integration["meta"]["keywords"] if "keywords" in integration["meta"] else None
204
205 md = f"""<!--startmeta
206 meta_yaml: "{meta_yaml}"
207 sidebar_label: "{sidebar_label}"
208 learn_status: "Published"
209 learn_rel_path: "{learn_rel_path}"
210 """
211 if keywords:
212 md += f"keywords: {keywords}\n"
213
214 md += f"""message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
215 endmeta-->
216
217 {create_overview(integration, integration['meta']['monitored_instance']['icon_filename'])}"""
218
219 if integration.get("setup"):
220 md += f"\n{integration['setup']}\n"
221 if integration.get("alerts"):
222 md += f"\n{integration['alerts']}\n"
223 if integration.get("metrics"):
224 md += f"\n{integration['metrics']}\n"
225 if integration.get("functions"):
226 md += f"\n{integration['functions']}\n"
227 if integration.get("troubleshooting"):
228 md += f"\n{integration['troubleshooting']}\n"
229
230 elif mode == "flows":
231 meta_yaml = integration["edit_link"].replace("blob", "edit")
232 sidebar_label = integration["meta"]["monitored_instance"]["name"]
233 learn_rel_path = generate_category_from_name(
234 integration["meta"]["monitored_instance"]["categories"][0].split("."), categories
235 )
236 keywords = integration["meta"]["keywords"] if "keywords" in integration["meta"] else None
237
238 md = f"""<!--startmeta
239 meta_yaml: "{meta_yaml}"
240 sidebar_label: "{sidebar_label}"
241 learn_status: "Published"
242 learn_rel_path: "{learn_rel_path}"
243 """
244 if keywords:
245 md += f"keywords: {keywords}\n"
246
247 md += f"""message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE FLOWS' metadata.yaml FILE"
248 endmeta-->
249
250 <!-- markdownlint-disable-file -->
251
252 {create_overview(integration, integration['meta']['monitored_instance']['icon_filename'])}"""
253
254 if integration.get("setup"):
255 md += f"\n{integration['setup']}\n"
256 if integration.get("troubleshooting"):
257 md += f"\n{integration['troubleshooting']}\n"
258
259 elif mode == "exporter":
260 meta_yaml = integration["edit_link"].replace("blob", "edit")
261 sidebar_label = integration["meta"]["name"]
262 learn_rel_path = generate_category_from_name(
263 integration["meta"]["categories"][0].split("."), categories
264 )
265 keywords = integration["keywords"] if "keywords" in integration else None
266
267 md = f"""<!--startmeta
268 meta_yaml: "{meta_yaml}"
269 sidebar_label: "{sidebar_label}"
270 learn_status: "Published"
271 learn_rel_path: "Exporting Metrics/Connectors"
272 """
273 if keywords:
274 md += f"keywords: {keywords}\n"
275
276 md += f"""message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE EXPORTER'S metadata.yaml FILE"
277 endmeta-->
278
279 {create_overview(integration, integration['meta']['icon_filename'])}"""
280
281 if integration.get("setup"):
282 md += f"\n{integration['setup']}\n"
283 if integration.get("troubleshooting"):
284 md += f"\n{integration['troubleshooting']}\n"
285
286 elif mode == "agent-notification":
287 meta_yaml = integration["edit_link"].replace("blob", "edit")
288 sidebar_label = integration["meta"]["name"]
289 learn_rel_path = generate_category_from_name(
290 integration["meta"]["categories"][0].split("."), categories
291 )
292 keywords = integration["keywords"] if "keywords" in integration else None
293
294 md = f"""<!--startmeta
295 meta_yaml: "{meta_yaml}"
296 sidebar_label: "{sidebar_label}"
297 learn_status: "Published"
298 learn_rel_path: "{learn_rel_path.replace("notifications", "Alerts & Notifications/Notifications")}"
299 """
300 if keywords:
301 md += f"keywords: {keywords}\n"
302
303 md += f"""message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE NOTIFICATION'S metadata.yaml FILE"
304 endmeta-->
305
306 {create_overview(integration, integration['meta']['icon_filename'], "overview")}"""
307
308 if integration.get("setup"):
309 md += f"\n{integration['setup']}\n"
310 if integration.get("troubleshooting"):
311 md += f"\n{integration['troubleshooting']}\n"
312
313 elif mode == "cloud-notification":
314 meta_yaml = integration["edit_link"].replace("blob", "edit")
315 sidebar_label = integration["meta"]["name"]
316 learn_rel_path = generate_category_from_name(
317 integration["meta"]["categories"][0].split("."), categories
318 )
319 keywords = integration["keywords"] if "keywords" in integration else None
320
321 md = f"""<!--startmeta
322 meta_yaml: "{meta_yaml}"
323 sidebar_label: "{sidebar_label}"
324 learn_status: "Published"
325 learn_rel_path: "{learn_rel_path.replace("notifications", "Alerts & Notifications/Notifications")}"
326 """
327 if keywords:
328 md += f"keywords: {keywords}\n"
329
330 md += f"""message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE NOTIFICATION'S metadata.yaml FILE"
331 endmeta-->
332
333 {create_overview(integration, integration['meta']['icon_filename'], "")}"""
334
335 if integration.get("setup"):
336 md += f"\n{integration['setup']}\n"
337 if integration.get("troubleshooting"):
338 md += f"\n{integration['troubleshooting']}\n"
339
340 elif mode == "logs":
341 meta_yaml = integration["edit_link"].replace("blob", "edit")
342 sidebar_label = integration["meta"]["name"]
343 learn_rel_path = generate_category_from_name(
344 integration["meta"]["categories"][0].split("."), categories
345 )
346 keywords = integration["keywords"] if "keywords" in integration else None
347
348 md = f"""<!--startmeta
349 meta_yaml: "{meta_yaml}"
350 sidebar_label: "{sidebar_label}"
351 learn_status: "Published"
352 learn_rel_path: "{learn_rel_path.replace("logs", "Logs")}"
353 """
354 if keywords:
355 md += f"keywords: {keywords}\n"
356
357 md += f"""message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE LOGS' metadata.yaml FILE"
358 endmeta-->
359
360 {create_overview(integration, integration['meta']['icon_filename'])}"""
361
362 if integration.get("setup"):
363 md += f"\n{integration['setup']}\n"
364
365 elif mode == "authentication":
366 meta_yaml = integration["edit_link"].replace("blob", "edit")
367 sidebar_label = integration["meta"]["name"]
368 learn_rel_path = generate_category_from_name(
369 integration["meta"]["categories"][0].split("."), categories
370 )
371 keywords = integration["keywords"] if "keywords" in integration else None
372
373 md = f"""<!--startmeta
374 meta_yaml: "{meta_yaml}"
375 sidebar_label: "{sidebar_label}"
376 learn_status: "Published"
377 learn_rel_path: "{learn_rel_path.replace("authentication", "Netdata Cloud/Authentication & Authorization/Cloud Authentication & Authorization Integrations")}"
378 """
379 if keywords:
380 md += f"keywords: {keywords}\n"
381
382 md += f"""message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE AUTHENTICATION'S metadata.yaml FILE"
383 endmeta-->
384
385 {create_overview(integration, integration['meta']['icon_filename'])}"""
386
387 if integration.get("setup"):
388 md += f"\n{integration['setup']}\n"
389 if integration.get("troubleshooting"):
390 md += f"\n{integration['troubleshooting']}\n"
391
392 elif mode == "secretstore":
393 meta_yaml = integration["edit_link"].replace("blob", "edit")
394 sidebar_label = integration["meta"]["name"]
395 learn_rel_path = "Collecting Metrics/Secrets Management/Secret Stores"
396 keywords = integration["keywords"] if "keywords" in integration else None
397
398 md = f"""<!--startmeta
399 meta_yaml: "{meta_yaml}"
400 sidebar_label: "{sidebar_label}"
401 learn_status: "Published"
402 learn_rel_path: "{learn_rel_path}"
403 """
404 if keywords:
405 md += f"keywords: {keywords}\n"
406
407 md += """message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE SECRETSTORE'S metadata.yaml FILE"
408 endmeta-->
409
410 """
411 md += create_overview(integration, integration['meta']['icon_filename'])
412
413 if integration.get("setup"):
414 md += f"\n{integration['setup']}\n"
415 if integration.get("collector_configs"):
416 md += f"\n{integration['collector_configs']}\n"
417 if integration.get("troubleshooting"):
418 md += f"\n{integration['troubleshooting']}\n"
419
420 elif mode == "service_discovery":
421 meta_yaml = integration["edit_link"].replace("blob", "edit")
422 sidebar_label = integration["meta"]["name"]
423 learn_rel_path = "Collecting Metrics/Service Discovery"
424 keywords = integration["keywords"] if "keywords" in integration else None
425
426 md = f"""<!--startmeta
427 meta_yaml: "{meta_yaml}"
428 sidebar_label: "{sidebar_label}"
429 learn_status: "Published"
430 learn_rel_path: "{learn_rel_path}"
431 """
432 if keywords:
433 md += f"keywords: {keywords}\n"
434
435 md += """message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE SERVICE DISCOVERY DISCOVERER'S metadata.yaml FILE"
436 endmeta-->
437
438 """
439 md += create_overview(integration, integration['meta']['icon_filename'])
440
441 if integration.get("setup"):
442 md += f"\n{integration['setup']}\n"
443 if integration.get("services"):
444 md += f"\n{integration['services']}\n"
445 if integration.get("verify"):
446 md += f"\n{integration['verify']}\n"
447 if integration.get("troubleshooting"):
448 md += f"\n{integration['troubleshooting']}\n"
449
450 except Exception as e:
451 print("Exception building md", e, integration.get("id"))
452
453 # Community badge
454 community = '<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />'
455 if "community" in integration["meta"]:
456 community = '<img src="https://img.shields.io/badge/maintained%20by-Community-blue" />'
457
458 return meta_yaml, sidebar_label, learn_rel_path, md, community
459
460
461 def create_overview_banner(md: str, community_badge: str) -> str:
462 """
463 Insert the community badge right before the first '##' section.
464 """
465 if "##" not in md:
466 return f"{md}\n\n{community_badge}\n"
467 upper, lower = md.split("##", 1)
468 return f"{upper}{community_badge}\n\n##{lower}"
469
470
471 def write_to_file(path: str, md: str, meta_yaml: str, sidebar_label: str, community: str, integration=None,
472 mode: str = "default", integration_id: str = None, output_slug: str = None):
473 """
474 Write the generated markdown into an `integrations/` subdirectory located alongside the `metadata.yaml` file.
475 This mirrors the original behavior of placing docs next to their source metadata.
476 Also registers the actual output path in id_to_path for later link resolution.
477 """
478 md = create_overview_banner(md, community)
479
480 if mode == "default":
481 base = Path(path)
482 if base.exists():
483 integrations_dir = base / "integrations"
484 integrations_dir.mkdir(exist_ok=True)
485 slug = output_slug or clean_string(sidebar_label)
486
487 try:
488 md2 = add_custom_edit_url(md, meta_yaml, sidebar_label, output_slug=slug)
489 outfile = integrations_dir / f"{slug}.md"
490 clean_and_write(md2, outfile)
491 if integration_id:
492 id_to_path[integration_id] = str(outfile)
493 except FileNotFoundError as e:
494 print("Exception in writing to file", e)
495
496 # If there's only one file inside the directory, register it for README symlink
497 if len(list(integrations_dir.iterdir())) == 1:
498 symlink_dict.update({path: f"integrations/{slug}.md"})
499 else:
500 try:
501 symlink_dict.pop(path)
502 except KeyError:
503 pass
504
505 elif mode == "cloud-notification":
506 name = clean_string(integration["meta"]["name"])
507 base = Path(path)
508 integrations_dir = base / "integrations"
509 integrations_dir.mkdir(exist_ok=True)
510 md2 = add_custom_edit_url(md, meta_yaml, sidebar_label, mode="cloud-notification")
511 finalpath = integrations_dir / f"{name}.md"
512 try:
513 clean_and_write(md2, finalpath)
514 if integration_id:
515 id_to_path[integration_id] = str(finalpath)
516 except FileNotFoundError as e:
517 print("Exception in writing to file", e)
518
519 elif mode == "agent-notification":
520 md2 = add_custom_edit_url(md, meta_yaml, sidebar_label, mode="agent-notification")
521 finalpath = Path(path) / "README.md"
522 try:
523 clean_and_write(md2, finalpath)
524 if integration_id:
525 id_to_path[integration_id] = str(finalpath)
526 except FileNotFoundError as e:
527 print("Exception in writing to file", e)
528
529 elif mode == "logs":
530 name = clean_string(integration["meta"]["name"])
531 base = Path(path)
532 integrations_dir = base / "integrations"
533 integrations_dir.mkdir(exist_ok=True)
534 md2 = add_custom_edit_url(md, meta_yaml, sidebar_label, mode="logs")
535 finalpath = integrations_dir / f"{name}.md"
536 try:
537 clean_and_write(md2, finalpath)
538 if integration_id:
539 id_to_path[integration_id] = str(finalpath)
540 except FileNotFoundError as e:
541 print("Exception in writing to file", e)
542
543 elif mode == "authentication":
544 name = clean_string(integration["meta"]["name"])
545 base = Path(path)
546 integrations_dir = base / "integrations"
547 integrations_dir.mkdir(exist_ok=True)
548 md2 = add_custom_edit_url(md, meta_yaml, sidebar_label, mode="cloud-authentication")
549 finalpath = integrations_dir / f"{name}.md"
550 try:
551 clean_and_write(md2, finalpath)
552 if integration_id:
553 id_to_path[integration_id] = str(finalpath)
554 except FileNotFoundError as e:
555 print("Exception in writing to file", e)
556
557
558 def make_symlinks(symlinks: dict):
559 """
560 Create README.md symlinks to the sole file in each /integrations dir.
561 """
562 for element in symlinks:
563 readme = Path(element) / "README.md"
564 if not readme.exists():
565 readme.touch()
566 try:
567 readme.unlink()
568 except FileNotFoundError:
569 pass
570
571 readme.symlink_to(symlinks[element])
572
573 filepath = Path(element) / symlinks[element]
574 md = filepath.read_text()
575 filepath.write_text(md.replace(f"{element}/{symlinks[element]}", f"{element}/README.md"))
576
577
578 # -----------------------------
579 # Filtering helpers
580 # -----------------------------
581 def _base_paths_for_collector(integrations, collector_key: str):
582 """
583 Return local base paths (without /integrations) for a single collector key: 'plugin/module'
584 """
585 if not collector_key:
586 return []
587 paths = []
588 for integ in integrations:
589 if integ.get("integration_type") != "collector":
590 continue
591 meta = integ.get("meta", {})
592 plugin = meta.get("plugin_name")
593 module = meta.get("module_name")
594 if not plugin or not module:
595 continue
596 key = f"{plugin}/{module}"
597 if key == collector_key:
598 meta_yaml = integ.get("edit_link", "").replace("blob", "edit")
599 base = build_path(meta_yaml)
600 paths.append(base)
601 return paths
602
603
604 # -----------------------------
605 # CLI entry
606 # -----------------------------
607 def main():
608 parser = argparse.ArgumentParser(description="Generate integration docs from metadata.yaml files.")
609 parser.add_argument(
610 "-c",
611 "--collector",
612 help="Generate docs only for this collector (plugin/module), e.g. 'go.d.plugin/snmp' or 'apps.plugin/groups'",
613 default=None,
614 )
615 args = parser.parse_args()
616
617 categories, integrations = read_integrations_js("integrations/integrations.js")
618
619 if args.collector:
620 # compute targets and CLEAN ONLY those
621 only_paths = _base_paths_for_collector(integrations, args.collector)
622 if not only_paths:
623 print(f"No matching collector found for: {args.collector}")
624 sys.exit(0)
625 cleanup(only_paths)
626 else:
627 # full cleanup (legacy behavior)
628 cleanup()
629
630 # Generate (pass 1: write all files, record id → actual output path)
631 for integration in integrations:
632 itype = integration.get("integration_type")
633 iid = integration.get("id")
634
635 # If -c is used, process ONLY the matching collector; skip everything else
636 if args.collector:
637 if itype != "collector":
638 continue
639 meta = integration.get("meta", {})
640 plugin = meta.get("plugin_name")
641 module = meta.get("module_name")
642 if not plugin or not module or f"{plugin}/{module}" != args.collector:
643 continue
644
645 if itype == "collector":
646 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
647 integration, categories, mode="collector"
648 )
649 path = build_path(meta_yaml)
650 write_to_file(path, md, meta_yaml, sidebar_label, community, integration_id=iid)
651
652 elif itype == "flows" and not args.collector:
653 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
654 integration, categories, mode="flows"
655 )
656 path = build_path(meta_yaml)
657 write_to_file(path, md, meta_yaml, sidebar_label, community, integration_id=iid)
658
659 elif itype == "exporter" and not args.collector:
660 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
661 integration, categories, mode="exporter"
662 )
663 path = build_path(meta_yaml)
664 write_to_file(path, md, meta_yaml, sidebar_label, community, integration_id=iid)
665
666 elif itype == "secretstore" and not args.collector:
667 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
668 integration, categories, mode="secretstore"
669 )
670 path = build_path(meta_yaml)
671 write_to_file(
672 path,
673 md,
674 meta_yaml,
675 sidebar_label,
676 community,
677 integration_id=iid,
678 output_slug=clean_string(integration["meta"]["kind"]),
679 )
680
681 elif itype == "service_discovery" and not args.collector:
682 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
683 integration, categories, mode="service_discovery"
684 )
685 path = build_path(meta_yaml)
686 write_to_file(
687 path,
688 md,
689 meta_yaml,
690 sidebar_label,
691 community,
692 integration_id=iid,
693 output_slug=clean_string(integration["meta"]["kind"]),
694 )
695
696 elif itype == "agent_notification" and not args.collector:
697 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
698 integration, categories, mode="agent-notification"
699 )
700 path = build_path(meta_yaml)
701 write_to_file(path, md, meta_yaml, sidebar_label, community, integration=integration,
702 mode="agent-notification", integration_id=iid)
703
704 elif itype == "cloud_notification" and not args.collector:
705 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
706 integration, categories, mode="cloud-notification"
707 )
708 path = build_path(meta_yaml)
709 write_to_file(path, md, meta_yaml, sidebar_label, community, integration=integration,
710 mode="cloud-notification", integration_id=iid)
711
712 elif itype == "logs" and not args.collector:
713 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
714 integration, categories, mode="logs"
715 )
716 path = build_path(meta_yaml)
717 write_to_file(path, md, meta_yaml, sidebar_label, community, integration=integration,
718 mode="logs", integration_id=iid)
719
720 elif itype == "authentication" and not args.collector:
721 meta_yaml, sidebar_label, learn_rel_path, md, community = build_readme_from_integration(
722 integration, categories, mode="authentication"
723 )
724 path = build_path(meta_yaml)
725 write_to_file(path, md, meta_yaml, sidebar_label, community, integration=integration,
726 mode="authentication", integration_id=iid)
727
728 # Pass 2: resolve relatedResource tags to markdown links now that all paths are known
729 resolve_related_links()
730
731 make_symlinks(symlink_dict)
732
733
734 if __name__ == "__main__":
735 main()