feat: merge all documentation functionality, leverage __doc__ for Pulumi modules
ZeroDownTime/CloudBender/pipeline/head This commit looks good Details

This commit is contained in:
Stefan Reimer 2022-06-30 17:42:49 +02:00
parent ac51a0774a
commit adc92bf24a
3 changed files with 121 additions and 105 deletions

View File

@ -26,11 +26,11 @@ clean:
pybuild: pybuild:
hatchling build hatchling build
test_upload: $(PACKAGE_FILE) test_upload: pybuild
twine upload --repository-url https://test.pypi.org/legacy/ dist/cloudbender-*.whl twine upload --repository-url https://test.pypi.org/legacy/ --non-interactive dist/cloudbender-*.whl
upload: $(PACKAGE_FILE) upload: pybuild
twine upload --repository-url https://upload.pypi.org/legacy/ dist/cloudbender-*.whl twine upload -r pypi --non-interactive dist/cloudbender-*.whl
build: build:
podman build --rm -t $(REPOSITORY):$(TAG) -t $(REPOSITORY):latest . podman build --rm -t $(REPOSITORY):$(TAG) -t $(REPOSITORY):latest .

View File

@ -145,12 +145,12 @@ def outputs(cb, stack_names, multi, include, values):
@click.option("--multi", is_flag=True, help="Allow more than one stack to match") @click.option("--multi", is_flag=True, help="Allow more than one stack to match")
@click.option("--graph", is_flag=True, help="Create Dot Graph file") @click.option("--graph", is_flag=True, help="Create Dot Graph file")
@click.pass_obj @click.pass_obj
def create_docs(cb, stack_names, multi, graph): def docs(cb, stack_names, multi, graph):
"""Parses all documentation fragments out of rendered templates creating docs/*.md file""" """Outputs docs for stack(s). For Pulumi stacks prints out docstring. For CloudFormation templates render a markdown file. Same idea as helm-docs."""
stacks = _find_stacks(cb, stack_names, multi) stacks = _find_stacks(cb, stack_names, multi)
for s in stacks: for s in stacks:
s.create_docs(graph=graph) s.docs(graph=graph)
@click.command() @click.command()
@ -183,19 +183,14 @@ def refresh(cb, stack_name):
@click.argument("stack_name") @click.argument("stack_name")
@click.argument("function", default="") @click.argument("function", default="")
@click.argument("args", nargs=-1) @click.argument("args", nargs=-1)
@click.option(
"--listall",
is_flag=True,
help="List all available execute functions for this stack",
)
@click.pass_obj @click.pass_obj
def execute(cb, stack_name, function, args, listall=False): def execute(cb, stack_name, function, args):
"""Executes custom Python function within an existing stack context""" """Executes custom Python function within an existing stack context"""
stacks = _find_stacks(cb, [stack_name]) stacks = _find_stacks(cb, [stack_name])
for s in stacks: for s in stacks:
if s.mode == "pulumi": if s.mode == "pulumi":
s.execute(function, args, listall) s.execute(function, args)
else: else:
logger.info( logger.info(
"{} uses Cloudformation, no exec feature available.".format(s.stackname) "{} uses Cloudformation, no exec feature available.".format(s.stackname)
@ -455,7 +450,7 @@ cli.add_command(delete)
cli.add_command(clean) cli.add_command(clean)
cli.add_command(create_change_set) cli.add_command(create_change_set)
cli.add_command(outputs) cli.add_command(outputs)
cli.add_command(create_docs) cli.add_command(docs)
cli.add_command(refresh) cli.add_command(refresh)
cli.add_command(preview) cli.add_command(preview)
cli.add_command(set_config) cli.add_command(set_config)

View File

@ -574,12 +574,31 @@ class Stack(object):
) )
) )
def create_docs(self, template=False, graph=False): @pulumi_ws
def docs(self, template=False, graph=False):
"""Read rendered template, parse documentation fragments, eg. parameter description """Read rendered template, parse documentation fragments, eg. parameter description
and create a mardown doc file for the stack and create a mardown doc file for the stack. Same idea as helm-docs for the values.yaml
same idea as eg. helm-docs for values.yaml
""" """
if self.mode == "pulumi":
if vars(self._pulumi_code)["__doc__"]:
print(vars(self._pulumi_code)["__doc__"])
else:
print("No template documentation found.")
# collect all __doc__ from available _execute_ functions
_help = ""
for k in vars(self._pulumi_code).keys():
if k.startswith("_execute_"):
docstring = vars(self._pulumi_code)[k].__doc__
_help = _help + "## {}\n{}\n".format(
k.lstrip("_execute_"), docstring
)
if _help:
print(f"# Available `execute` functions: \n\n{_help}")
else:
try: try:
self.read_template_file() self.read_template_file()
except FileNotFoundError: except FileNotFoundError:
@ -627,7 +646,9 @@ class Stack(object):
with open(doc_file, "w") as doc_contents: with open(doc_file, "w") as doc_contents:
doc_contents.write(template.render(**data)) doc_contents.write(template.render(**data))
logger.info("Wrote documentation for %s to %s", self.stackname, doc_file) logger.info(
"Wrote documentation for %s to %s", self.stackname, doc_file
)
# Write Graph in Dot format # Write Graph in Dot format
if graph: if graph:
@ -636,9 +657,15 @@ class Stack(object):
) )
lint_args = ["--template", filename] lint_args = ["--template", filename]
(args, filenames, formatter) = cfnlint.core.get_args_filenames(lint_args) (args, filenames, formatter) = cfnlint.core.get_args_filenames(
(template, rules, matches) = cfnlint.core.get_template_rules(filename, args) lint_args
template_obj = cfnlint.template.Template(filename, template, [self.region]) )
(template, rules, matches) = cfnlint.core.get_template_rules(
filename, args
)
template_obj = cfnlint.template.Template(
filename, template, [self.region]
)
path = os.path.join( path = os.path.join(
self.ctx["docs_path"], self.rel_path, self.stackname + ".dot" self.ctx["docs_path"], self.rel_path, self.stackname + ".dot"
@ -867,18 +894,14 @@ class Stack(object):
return return
@pulumi_ws @pulumi_ws
def execute(self, function, args, listall=False): def execute(self, function, args):
"""Executes custom Python function within a Pulumi stack""" """
Executes custom Python function within a Pulumi stack
# call all available functions and output built in help These functions are executed within the stack environment and are provided with all stack input parameters as well as current outputs.
if listall: Think of "docker exec" into an existing container...
for k in vars(self._pulumi_code).keys():
if k.startswith("_execute_"):
docstring = vars(self._pulumi_code)[k](docstring=True)
print("{}: {}".format(k.lstrip("_execute_"), docstring))
return
else: """
if not function: if not function:
logger.error("No function specified !") logger.error("No function specified !")
return return
@ -893,9 +916,7 @@ class Stack(object):
) )
else: else:
logger.error( logger.error("{} is not defined in {}".format(function, self._pulumi_code))
"{} is not defined in {}".format(function, self._pulumi_code)
)
@pulumi_ws @pulumi_ws
def assimilate(self): def assimilate(self):