Skip to content

Commit

Permalink
Merge pull request #2 from dapr/additional_improvements
Browse files Browse the repository at this point in the history
Additional improvements
  • Loading branch information
artursouza committed Jan 16, 2021
2 parents d0737aa + f2bda5d commit 58e097e
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 10 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/build.yaml
Expand Up @@ -2,8 +2,6 @@ name: mechanical-markdown

on:
push:
branches:
- main
tags:
- v*
pull_request:
Expand All @@ -16,8 +14,8 @@ jobs:
runs-on: ubuntu-latest
env:
PYTHON_VER: 3.7
TWINE_USERNAME: ${{ secrets.PYPI_UPLOAD_USER }}
TWINE_PASSWORD: ${{ secrets.PYPI_UPLOAD_PASS }}
TWINE_USERNAME: "__token__"
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ env.PYTHON_VER }}
Expand Down
2 changes: 1 addition & 1 deletion README.md
@@ -1,6 +1,6 @@
# Mechanical Markdown

[![codecov](https://codecov.io/gh/wcs1only/mechanical-markdown/branch/main/graph/badge.svg)](https://codecov.io/gh/wcs1only/mechanical-markdown)
[![codecov](https://codecov.io/gh/dapr/mechanical-markdown/branch/main/graph/badge.svg)](https://codecov.io/gh/dapr/mechanical-markdown)

If you are using markdown to create tutorials for your users, these markdown files will often be a series of shell commands that a user will copy and paste into their shell of choice, along with detailed text description of what each command is doing.

Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Expand Up @@ -154,6 +154,7 @@ expected_stdout_lines:
- "Would run the following validation steps:"
- "Step: Hello World"
- "Step: CLI help"
- "Step: CLI version"
- "Step: CLI dry run"
- "Step: Pause for manual validation"
-->
Expand Down
31 changes: 31 additions & 0 deletions examples/io.md
@@ -1,5 +1,6 @@
# I/O Validation

## Using This Guide
This is an example markdown file with an annotated test command.

To see a summary of what commands will be run:
Expand All @@ -16,6 +17,8 @@ mm.py io.md

Be sure to checkout the raw version of this file to see the annotations.

## Checking stdout/stderr

This is an annotated command. When the ```mm.py``` utility is run, the following code block will be executed:

<!-- STEP
Expand Down Expand Up @@ -53,6 +56,34 @@ echo "error" 1>&2

<!-- END_STEP -->

## Checking return code

By default, all code blocks are expected to return 0. You can change this behavior with the directive ```expected_return_code```:

<!-- STEP
name: Non-zero Return Code
expected_return_code: 1
-->

```bash
exit 1
```

<!-- END_STEP -->

A missing or null value for ```expected_return_code``` will ignore all return codes.

<!-- STEP
name: Ignore Return Code
expected_return_code:
-->

```bash
exit 15
```

<!-- END_STEP -->

# Navigation

* Back to [README](README.md)
Expand Down
2 changes: 1 addition & 1 deletion mechanical_markdown/__init__.py
Expand Up @@ -7,6 +7,6 @@
from mechanical_markdown.recipe import Recipe as MechanicalMarkdown
from mechanical_markdown.parsers import MarkdownAnnotationError

__version__ = '0.1.8'
__version__ = '0.2.2'

__all__ = [MechanicalMarkdown, MarkdownAnnotationError]
11 changes: 8 additions & 3 deletions mechanical_markdown/step.py
Expand Up @@ -29,6 +29,7 @@ def __init__(self, parameters):
self.expected_lines['stdout'] = parameters["expected_stdout_lines"]
if "expected_stderr_lines" in parameters and parameters["expected_stderr_lines"] is not None:
self.expected_lines['stderr'] = parameters["expected_stderr_lines"]
self.expect_return_code = 0 if "expected_return_code" not in parameters else parameters["expected_return_code"]
self.working_dir = os.getcwd() if "working_dir" not in parameters else parameters["working_dir"]
self.timeout = default_timeout_seconds if "timeout_seconds" not in parameters else parameters["timeout_seconds"]
self.env = dict(os.environ, **parameters['env']) if "env" in parameters else os.environ
Expand All @@ -50,7 +51,7 @@ def run_all_commands(self, manual, shell):
command.run(self.working_dir, self.env, shell)
if not self.background:
command.wait_or_timeout(self.timeout)
if command.return_code != 0:
if self.expect_return_code is not None and command.return_code != self.expect_return_code:
return False
if self.sleep:
time.sleep(self.sleep)
Expand All @@ -69,14 +70,16 @@ def dryrun(self, shell):
for expected in self.expected_lines[out]:
retstr += "\t\t{}\n".format(expected)

retstr += "\tExpected return code: {}\n".format(self.expect_return_code)

return retstr + "\n"

def wait_for_all_background_commands(self):
success = True
for command in self.commands:
if self.background:
command.wait_or_timeout(self.timeout)
if command.return_code != 0:
if self.expect_return_code is not None and command.return_code != self.expect_return_code:
success = False
return success

Expand All @@ -89,7 +92,9 @@ def validate_and_report(self):
for c in self.commands:
if c.process is not None:
color = 'green'
if c.return_code != 0:
if self.expect_return_code is None:
color = 'yellow'
elif c.return_code != self.expect_return_code:
color = 'red'
report += "\tcommand: `{}`\n\treturn_code: {}\n".format(c.command, colored(c.return_code, color))

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -23,7 +23,7 @@
description="Run markdown recipes as shell scripts",
long_description=README,
long_description_content_type="text/markdown",
url="https://github.com/wcs1only/mechanical-markdown",
url="https://github.com/dapr/mechanical-markdown",
author="Charlie Stanley",
author_email="Charlie.Stanley@microsoft.com",
license="MIT",
Expand Down
44 changes: 44 additions & 0 deletions tests/test_mechanical_markdown.py
Expand Up @@ -344,6 +344,7 @@ def test_dryrun(self):
\t\ttest
\t\ttest2
\tExpected stderr:
\tExpected return code: 0
Step: step 2
\tcommands to run with 'bash -c':
Expand All @@ -353,6 +354,7 @@ def test_dryrun(self):
\t\tfoo
\tExpected stderr:
\t\tbar
\tExpected return code: 0
"""
self.assertEqual(expected_output, output)
Expand Down Expand Up @@ -468,3 +470,45 @@ def test_missing_extra_tag_throws_exception(self):
"""
with self.assertRaises(MarkdownAnnotationError):
MechanicalMarkdown(test_data)

def test_expect_status_code_success(self):
test_data = """
<!-- STEP
name: expect returns 1
expected_return_code: 1
-->
```bash
exit 1
```
<!-- END_STEP -->
<!-- STEP
name: ignore return code
expected_return_code:
-->
```bash
exit 15
```
<!-- END_STEP -->
"""
self.prep_command_ouput("test", "", 1)
self.prep_command_ouput("test", "", 15)
mm = MechanicalMarkdown(test_data)
success, report = mm.exectute_steps(False)
self.assertTrue(success)
calls = [call(['bash', '-c', 'exit 1'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
env=os.environ),
call().communicate(timeout=60),
call(['bash', '-c', 'exit 15'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
env=os.environ)]
self.popen_mock.assert_has_calls(calls)

0 comments on commit 58e097e

Please sign in to comment.