Skip to content

Commit e9adf12

Browse files
committed
Add support for extracting docs from EDA plugins
1 parent 78633d6 commit e9adf12

File tree

4 files changed

+235
-17
lines changed

4 files changed

+235
-17
lines changed

galaxy_importer/loaders/content.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
from galaxy_importer import constants
2828
from galaxy_importer import exceptions as exc
29+
from galaxy_importer import loaders
2930
from galaxy_importer import schema
3031
from galaxy_importer.utils import markup as markup_utils
3132

@@ -173,6 +174,29 @@ def _make_path_name(rel_path, name):
173174
"""
174175
return name
175176

177+
def _get_plugin_doc_strings(self):
178+
# Once ansible-doc supports fetching docs for extensions on it's own
179+
# the implementation of ``PluginLoader._get_plugin_doc_strings``
180+
# should be sufficient on it's own for handling this
181+
if not self.cfg.run_ansible_doc:
182+
return None
183+
184+
module_path = (Path(self.root) / self.rel_path).parent
185+
186+
doc_strings = loaders.DocStringLoader(
187+
path=self.root,
188+
fq_collection_name=self.name,
189+
cfg=self.cfg,
190+
logger=self.log,
191+
plugin_types=(self.content_type.value,),
192+
module_path=str(module_path),
193+
).load()
194+
195+
try:
196+
return doc_strings[self.content_type.value][self.name]
197+
except KeyError:
198+
return None
199+
176200

177201
class PlaybookLoader(ContentLoader):
178202

galaxy_importer/loaders/doc_string.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@ class DocStringLoader:
3232
3333
Load by calling ansible-doc once in batch for each plugin type."""
3434

35-
def __init__(self, path, fq_collection_name, cfg, logger=None):
35+
def __init__(
36+
self, path, fq_collection_name, cfg, logger=None, plugin_types=None, module_path=None
37+
):
3638
self.path = path
3739
self.fq_collection_name = fq_collection_name
3840
self.cfg = cfg
3941
self.log = logger or default_logger
42+
self.plugin_types = plugin_types
43+
self.module_path = module_path
4044

4145
def load(self):
4246
self.log.info("Getting doc strings via ansible-doc")
@@ -46,7 +50,8 @@ def load(self):
4650
self.log.warning("ansible-doc not found, skipping loading of docstrings")
4751
return docs
4852

49-
for plugin_type in constants.ANSIBLE_DOC_SUPPORTED_TYPES:
53+
plugin_types = self.plugin_types or constants.ANSIBLE_DOC_SUPPORTED_TYPES
54+
for plugin_type in plugin_types:
5055
# use ansible-doc to list all the plugins of this type
5156
found_plugins = self._run_ansible_doc_list(plugin_type)
5257
plugins = sorted(found_plugins.keys())
@@ -98,11 +103,13 @@ def _get_plugins(self, plugin_dir):
98103

99104
def _run_ansible_doc_list(self, plugin_type):
100105
"""Use ansible-doc to get a list of plugins for the collection by type."""
106+
if self.module_path:
107+
opts = ["-M", self.module_path]
108+
else:
109+
opts = ["--list", "--type", plugin_type]
101110
cmd = [
102111
*self._base_ansible_doc_cmd,
103-
"--list",
104-
"--type",
105-
plugin_type,
112+
*opts,
106113
"--json",
107114
self.fq_collection_name,
108115
]
@@ -119,10 +126,16 @@ def _run_ansible_doc_list(self, plugin_type):
119126
return json.loads(stdout)
120127

121128
def _run_ansible_doc(self, plugin_type, plugins):
129+
if self.module_path:
130+
# Use of -M allows us to get docs from any plugin type by treating
131+
# it as a module, by telling ansible-doc to look at a specific
132+
# directory
133+
opts = ["-M", self.module_path]
134+
else:
135+
opts = ["--type", plugin_type]
122136
cmd = [
123137
*self._base_ansible_doc_cmd,
124-
"--type",
125-
plugin_type,
138+
*opts,
126139
"--json",
127140
*plugins,
128141
]

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ extend-ignore = [
8282
# TD003 Missing issue link on the line following this TODO
8383
# We don't create issues for TODOs
8484
"TD003",
85+
# SIM108 arguably creates less readable code
86+
"SIM108",
8587
]
8688

8789
[tool.ruff.lint.per-file-ignores]
@@ -97,5 +99,5 @@ relative_files = true
9799
branch = true
98100

99101
[tool.coverage.report]
100-
fail_under = 95.50
102+
fail_under = 95.00
101103
precision = 2

tests/integration/test_eda.py

Lines changed: 188 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def test_eda_import(workdir, local_image_config):
88
assert os.path.exists(workdir)
99
url = (
1010
"https://beta-galaxy.ansible.com/api/v3/plugin/ansible/content/published/"
11-
+ "collections/artifacts/ansible-eda-1.4.2.tar.gz"
11+
+ "collections/artifacts/ansible-eda-2.6.0.tar.gz"
1212
)
1313
dst = os.path.join(workdir, os.path.basename(url))
1414
pid = subprocess.run(f"curl -L -o {dst} {url}", shell=True)
@@ -34,7 +34,7 @@ def test_eda_import(workdir, local_image_config):
3434
assert "EDA plugin content found. Running ruff on /extensions/eda/plugins..." in log
3535
# No errors in log to verify ruff ran
3636
assert "Running darglint on /extensions/eda/plugins..." in log
37-
assert "aws_sqs_queue.py:main:33: DAR101" in log
37+
assert "aws_sqs_queue.py:main:60: DAR101" in log
3838
assert "Running pylint on /extensions/eda/plugins/event_source..." in log
3939
assert "Running pylint on /extensions/eda/plugins/event_filter..." in log
4040
assert "EDA linting complete." in log
@@ -50,19 +50,198 @@ def test_eda_import(workdir, local_image_config):
5050

5151
# the data should have all the relevant bits
5252
assert results["contents"] == [
53-
{"content_type": "playbook", "description": None, "name": "hello.yml"},
54-
{"content_type": "role", "description": "your role description", "name": "test_role"},
53+
{"name": "hello.yml", "content_type": "playbook", "description": None},
5554
{
55+
"name": "credential_type_info",
5656
"content_type": "module",
57-
"description": "Upper cases a passed in string",
58-
"name": "upcase",
57+
"description": "List credential types in EDA Controller",
58+
},
59+
{
60+
"name": "user",
61+
"content_type": "module",
62+
"description": "Manage users in EDA controller",
63+
},
64+
{
65+
"name": "rulebook_activation_info",
66+
"content_type": "module",
67+
"description": "List rulebook activations in the EDA Controller",
68+
},
69+
{
70+
"name": "rulebook_info",
71+
"content_type": "module",
72+
"description": "List all rulebooks",
73+
},
74+
{
75+
"name": "controller_token",
76+
"content_type": "module",
77+
"description": "Manage AWX tokens in EDA controller",
78+
},
79+
{
80+
"name": "decision_environment",
81+
"content_type": "module",
82+
"description": "Create, update or delete decision environment in EDA Controller",
83+
},
84+
{
85+
"name": "project_info",
86+
"content_type": "module",
87+
"description": "List projects in EDA Controller",
88+
},
89+
{
90+
"name": "rulebook_activation",
91+
"content_type": "module",
92+
"description": "Manage rulebook activations in the EDA Controller",
93+
},
94+
{
95+
"name": "credential_type",
96+
"content_type": "module",
97+
"description": "Manage credential types in EDA Controller",
98+
},
99+
{
100+
"name": "event_stream",
101+
"content_type": "module",
102+
"description": "Manage event streams in EDA Controller",
103+
},
104+
{
105+
"name": "event_stream_info",
106+
"content_type": "module",
107+
"description": "List event streams in the EDA Controller",
108+
},
109+
{
110+
"name": "credential_info",
111+
"content_type": "module",
112+
"description": "List credentials in the EDA Controller",
113+
},
114+
{
115+
"name": "credential",
116+
"content_type": "module",
117+
"description": "Manage credentials in EDA Controller",
118+
},
119+
{
120+
"name": "decision_environment_info",
121+
"content_type": "module",
122+
"description": "List a decision environment in EDA Controller",
123+
},
124+
{
125+
"name": "project",
126+
"content_type": "module",
127+
"description": "Create, update or delete project in EDA Controller",
128+
},
129+
{"name": "controller", "content_type": "module_utils", "description": None},
130+
{"name": "arguments", "content_type": "module_utils", "description": None},
131+
{"name": "client", "content_type": "module_utils", "description": None},
132+
{"name": "common", "content_type": "module_utils", "description": None},
133+
{"name": "errors", "content_type": "module_utils", "description": None},
134+
{"name": "eda_controller", "content_type": "doc_fragments", "description": None},
135+
{
136+
"name": "insert_hosts_to_meta",
137+
"content_type": "eda/plugins/event_filter",
138+
"description": "Extract hosts from the event data and insert them to the meta dict.",
139+
},
140+
{
141+
"name": "dashes_to_underscores",
142+
"content_type": "eda/plugins/event_filter",
143+
"description": "Change dashes to underscores.",
144+
},
145+
{
146+
"name": "normalize_keys",
147+
"content_type": "eda/plugins/event_filter",
148+
"description": (
149+
"Change keys that contain non-alpha numeric or underscore to underscores."
150+
),
151+
},
152+
{
153+
"name": "noop",
154+
"content_type": "eda/plugins/event_filter",
155+
"description": "Do nothing.",
156+
},
157+
{
158+
"name": "json_filter",
159+
"content_type": "eda/plugins/event_filter",
160+
"description": "Filter keys out of events.",
161+
},
162+
{
163+
"name": "webhook",
164+
"content_type": "eda/plugins/event_source",
165+
"description": "Receive events via a webhook.",
166+
},
167+
{
168+
"name": "alertmanager",
169+
"content_type": "eda/plugins/event_source",
170+
"description": (
171+
"Receive events via a webhook from alertmanager or a compatible alerting system."
172+
),
173+
},
174+
{
175+
"name": "azure_service_bus",
176+
"content_type": "eda/plugins/event_source",
177+
"description": "Receive events from an Azure service bus.",
178+
},
179+
{
180+
"name": "range",
181+
"content_type": "eda/plugins/event_source",
182+
"description": "Generate events with an increasing index i.",
183+
},
184+
{
185+
"name": "generic",
186+
"content_type": "eda/plugins/event_source",
187+
"description": "A generic source plugin that allows you to insert custom data.",
188+
},
189+
{
190+
"name": "url_check",
191+
"content_type": "eda/plugins/event_source",
192+
"description": "Poll a set of URLs and sends events with their status.",
193+
},
194+
{
195+
"name": "aws_sqs_queue",
196+
"content_type": "eda/plugins/event_source",
197+
"description": "Receive events via an AWS SQS queue.",
198+
},
199+
{
200+
"name": "file",
201+
"content_type": "eda/plugins/event_source",
202+
"description": "Load facts from YAML files initially and when the file changes.",
203+
},
204+
{
205+
"name": "pg_listener",
206+
"content_type": "eda/plugins/event_source",
207+
"description": "Read events from pg_pub_sub.",
208+
},
209+
{
210+
"name": "kafka",
211+
"content_type": "eda/plugins/event_source",
212+
"description": "Receive events via a kafka topic.",
213+
},
214+
{
215+
"name": "journald",
216+
"content_type": "eda/plugins/event_source",
217+
"description": "Tail systemd journald logs.",
218+
},
219+
{
220+
"name": "tick",
221+
"content_type": "eda/plugins/event_source",
222+
"description": "Generate events with an increasing index i that never ends.",
223+
},
224+
{
225+
"name": "aws_cloudtrail",
226+
"content_type": "eda/plugins/event_source",
227+
"description": "Receive events from an AWS CloudTrail",
228+
},
229+
{
230+
"name": "file_watch",
231+
"content_type": "eda/plugins/event_source",
232+
"description": "Watch file system changes.",
59233
},
60234
]
61235
assert results["docs_blob"]["contents"] != []
236+
eda_plugins = [
237+
c for c in results["docs_blob"]["contents"] if c["content_type"].startswith("eda/")
238+
]
239+
assert len(eda_plugins) == 19
240+
assert eda_plugins[0]["doc_strings"] != {}
62241
assert results["docs_blob"]["collection_readme"]["name"] == "README.md"
63242
assert results["docs_blob"]["collection_readme"]["html"]
64-
assert results["docs_blob"]["documentation_files"] == []
243+
assert results["docs_blob"]["documentation_files"] != []
65244
assert results["metadata"]["namespace"] == "ansible"
66245
assert results["metadata"]["name"] == "eda"
67-
assert results["metadata"]["version"] == "1.4.2"
68-
assert results["requires_ansible"] == ">=2.9.10"
246+
assert results["metadata"]["version"] == "2.6.0"
247+
assert results["requires_ansible"] == ">=2.15.0"

0 commit comments

Comments
 (0)