Skip to content

Commit ecd1831

Browse files
authored
Merge branch 'add-stylechecker' into coderabbitai/utg/da2fcbf
2 parents c79f251 + 42aaab2 commit ecd1831

16 files changed

+564
-61
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ coverage.xml
4747
*.cover
4848
.hypothesis/
4949
.pytest_cache/
50+
tests/output/
5051

5152
# Translations
5253
*.mo

.pre-commit-hooks.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- id: robot2rst-stylecheck
2+
name: Robot Framework RST Style Check
3+
description: Checks and fixes RST syntax/layout in Robot Framework [Documentation] blocks.
4+
entry: robot2rst stylecheck
5+
language: python
6+
files: \.robot$
7+
additional_dependencies: ["mlx.robot2rst[stylecheck]"]

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ exclude mlx/robot2rst/__version__.py
1010

1111
# added by check_manifest.py
1212
include tox.ini
13+
include .pre-commit-hooks.yaml
14+
recursive-include tests *.py
15+
recursive-include tests *.robot
16+
recursive-include tests *.rst

README.rst

Lines changed: 98 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,47 +34,115 @@ Usage
3434

3535
.. code-block:: console
3636
37-
robot2rst -i example.robot -o test_plan.rst --prefix ITEST_MY_LIB- \
38-
--tags SWRQT- SYSRQT- --relationships validates ext_toolname --coverage 100 66.66
39-
4037
$ robot2rst --help
4138
42-
usage: robot2rst [-h] -i ROBOT_FILE -o RST_FILE [--only EXPRESSION] [-p PREFIX]
43-
[-r [RELATIONSHIPS ...]] [-t [TAGS ...]] [--include [INCLUDE ...]]
44-
[-c [COVERAGE ...]] [--type TYPE] [--trim-suffix]
39+
usage: robot2rst [-h] {convert,stylecheck} ...
4540
4641
Convert robot test cases to reStructuredText with traceable items.
4742
43+
positional arguments:
44+
{convert,stylecheck} Available commands
45+
convert Converts a Robot Framework file to a reStructuredText (.rst) file (default).
46+
stylecheck Checks and fixes RST style in Robot documentation blocks.
47+
48+
options:
49+
-h, --help show this help message and exit
50+
51+
examples:
52+
# Convert a file (default command)
53+
robot2rst -i input.robot -o output.rst
54+
55+
# Explicitly call convert
56+
robot2rst convert -i input.robot -o output.rst
57+
58+
# Check style of all .robot files in the current directory and subdirectories
59+
robot2rst stylecheck --fix
60+
61+
62+
Conversion (Default)
63+
====================
64+
65+
To convert a Robot file to RST:
66+
67+
.. code-block:: console
68+
69+
robot2rst -i example.robot -o test_plan.rst --prefix ITEST_MY_LIB- \
70+
--tags SWRQT- SYSRQT- --relationships validates ext_toolname --coverage 100 66.66
71+
72+
$ robot2rst convert --help
73+
74+
usage: robot2rst convert [-h] -i ROBOT_FILE -o RST_FILE [--only EXPRESSION] [-p PREFIX]
75+
[-r [RELATIONSHIPS ...]] [-t [TAGS ...]] [--include [INCLUDE ...]]
76+
[-c [COVERAGE ...]] [--type TYPE] [--trim-suffix]
77+
4878
options:
49-
-h, --help show this help message and exit
50-
-i ROBOT_FILE, --robot ROBOT_FILE
79+
-h, --help show this help message and exit
80+
-i ROBOT_FILE, --robot ROBOT_FILE
5181
Input robot file
52-
-o RST_FILE, --rst RST_FILE
82+
-o RST_FILE, --rst RST_FILE
5383
Output RST file, e.g. my_component_qtp.rst
54-
--only EXPRESSION Expression of tags for Sphinx' `only` directive that surrounds all
55-
RST content. By default, no `only` directive is generated.
56-
-p PREFIX, --prefix PREFIX
84+
--only EXPRESSION Expression of tags for Sphinx' `only` directive that surrounds all RST content.
85+
-p PREFIX, --prefix PREFIX
5786
Overrides the default 'QTEST-' prefix.
58-
-r [RELATIONSHIPS ...], --relationships [RELATIONSHIPS ...]
59-
Name(s) of the relationship(s) used to link to items in Tags section.
60-
The default value is 'validates'.
61-
-t [TAGS ...], --tags [TAGS ...]
62-
Zero or more Python regexes for matching tags to treat them as
63-
traceable targets via a relationship. All tags get matched by
87+
-r [RELATIONSHIPS ...], --relationships [RELATIONSHIPS ...]
88+
Name(s) of the relationship(s) used to link to items in Tags section. Default:
89+
'validates'.
90+
-t [TAGS ...], --tags [TAGS ...]
91+
Python regexes for matching tags to treat as traceable targets. Matches all by
6492
default.
65-
--include [INCLUDE ...]
66-
Zero or more Python regexes for matching tags to filter test cases.
67-
If every regex matches at least one of a test case's tags, the test
68-
case is included.
69-
-c [COVERAGE ...], --coverage [COVERAGE ...]
70-
Minimum coverage percentages for the item-matrix(es); 1 value per tag
71-
in -t, --tags.
72-
--type TYPE Give value that starts with 'q' or 'i' (case-insensitive) to
73-
explicitly define the type of test: qualification/integration test.
74-
The default is 'qualification'.
75-
--trim-suffix If the suffix of any prefix or --tags argument ends with '_-' it gets
76-
trimmed to '-'.
93+
--include [INCLUDE ...]
94+
Python regexes for matching tags to filter test cases.
95+
-c [COVERAGE ...], --coverage [COVERAGE ...]
96+
Minimum coverage percentages for the item-matrix(es); 1 value per tag in --tags.
97+
--type TYPE Type of test ('q' for qualification, 'i' for integration). Default:
98+
'qualification'.
99+
--trim-suffix If the suffix of any prefix or --tags argument ends with '_-' it gets trimmed to
100+
'-'.
101+
102+
Style Checker & Fixer
103+
=====================
104+
105+
You can also check and automatically fix the RST syntax and layout within the ``[Documentation]`` blocks of your Robot files.
106+
107+
.. code-block:: console
108+
109+
# Check all .robot files in the current directory
110+
robot2rst stylecheck
111+
112+
# Automatically fix issues and set a custom line length
113+
robot2rst stylecheck --fix --line-length 120
114+
115+
$ robot2rst stylecheck --help
116+
117+
usage: robot2rst stylecheck [-h] [--fix] [--fail-on-layout] [--line-length LINE_LENGTH] [paths ...]
118+
119+
positional arguments:
120+
paths One or more paths to files or folders to check. Default: current directory.
121+
122+
options:
123+
-h, --help show this help message and exit
124+
--fix Automatically fix RST formatting inside Robot documentation blocks.
125+
--fail-on-layout Fail on RST layout issues as well as syntax issues.
126+
--line-length LINE_LENGTH
127+
Max line length for RST blocks (note: the line length does not include the length
128+
of the [Documentation] tag for example). Default: 100.
129+
130+
131+
---------------
132+
Pre-commit Hook
133+
---------------
134+
135+
You can use ``robot2rst`` as a pre-commit hook to ensure your Robot documentation stays correctly formatted.
136+
Add this to your ``.pre-commit-config.yaml``:
137+
138+
.. code-block:: yaml
77139
140+
repos:
141+
- repo: https://github.com/melexis/robot2rst
142+
rev: 3.7.0 # Use the latest stable release
143+
hooks:
144+
- id: robot2rst-stylecheck
145+
args: ["--fix", "--line-length", "100"]
78146
79147
-------------
80148
Configuration

mlx/robot2rst/robot2rst.py

Lines changed: 130 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,38 +79,56 @@ def _tweak_prefix(prefix):
7979
return prefix
8080

8181

82-
def main():
83-
'''Main entry point for script: parse arguments and execute'''
84-
parser = argparse.ArgumentParser(description='Convert robot test cases to reStructuredText with traceable items.')
85-
parser.add_argument("-i", "--robot", dest='robot_file', required=True,
86-
help='Input robot file')
87-
parser.add_argument("-o", "--rst", dest='rst_file', required=True,
88-
help='Output RST file, e.g. my_component_qtp.rst')
89-
parser.add_argument("--only", dest="expression", default="",
90-
help="Expression of tags for Sphinx' `only` directive that surrounds all RST content. "
91-
"By default, no `only` directive is generated.")
92-
parser.add_argument("-p", "--prefix", default='QTEST-',
93-
help="Overrides the default 'QTEST-' prefix.")
94-
parser.add_argument("-r", "--relationships", nargs='*',
95-
help="Name(s) of the relationship(s) used to link to items in Tags section. The default value "
96-
"is 'validates'.")
97-
parser.add_argument("-t", "--tags", nargs='*',
98-
help="Zero or more Python regexes for matching tags to treat them as traceable targets via a "
99-
"relationship. All tags get matched by default.")
100-
parser.add_argument("--include", nargs='*', default=[],
101-
help="Zero or more Python regexes for matching tags to filter test cases. "
102-
"If every regex matches at least one of a test case's tags, the test case is included.")
103-
parser.add_argument("-c", "--coverage", nargs='*',
104-
help="Minimum coverage percentages for the item-matrix(es); 1 value per tag in -t, --tags.")
105-
parser.add_argument("--type", default='q',
106-
help="Give value that starts with 'q' or 'i' (case-insensitive) to explicitly define "
107-
"the type of test: qualification/integration test. The default is 'qualification'.")
108-
parser.add_argument("--trim-suffix", action='store_true',
109-
help="If the suffix of any prefix or --tags argument ends with '_-' it gets trimmed to '-'.")
82+
def get_robot_files(paths):
83+
"""Yields Path objects for all robot files found in the input paths.
84+
85+
Args:
86+
paths (list of str): List of file or directory paths.
87+
88+
Yields:
89+
Path: Path object for each robot file found.
90+
"""
91+
for p in paths:
92+
path = Path(p)
93+
if path.is_file() and path.suffix == ".robot":
94+
yield path
95+
elif path.is_dir():
96+
yield from path.rglob("*.robot")
97+
98+
99+
def run_stylecheck(args):
100+
"""Runs the style checker and fixer."""
101+
try:
102+
from .style_checker import StyleChecker
103+
except ImportError:
104+
LOGGER.error("Missing packages. Install with 'pip install mlx.robot2rst[stylecheck]'")
105+
return 1
106+
107+
issues_found = False
108+
lint_issues_found = False
109+
files_checked = False
110+
for robot_file in get_robot_files(args.paths):
111+
files_checked = True
112+
style_kwargs = {"line_length": args.line_length}
113+
parser = StyleChecker(robot_file, fix=args.fix, **style_kwargs)
114+
parser.run()
115+
116+
if (parser.issues_found or parser.lint_issues_found) and args.fix:
117+
parser.model.save(robot_file)
118+
119+
if not (parser.issues_found or parser.lint_issues_found):
120+
LOGGER.info("%s: No RST syntax/layout issues found", robot_file)
121+
issues_found = issues_found or parser.issues_found
122+
lint_issues_found = lint_issues_found or parser.lint_issues_found
123+
124+
if not files_checked:
125+
LOGGER.warning("No Robot Framework files found to check.")
126+
127+
return 1 if issues_found or (args.fail_on_layout and lint_issues_found) else 0
110128

111-
logging.basicConfig(level=logging.INFO)
112-
args = parser.parse_args()
113129

130+
def run_conversion(args):
131+
"""Runs the robot to rst conversion."""
114132
type_map = {
115133
'i': 'integration',
116134
'q': 'qualification',
@@ -142,6 +160,7 @@ def main():
142160

143161
parser = ParserApplication(Path(args.robot_file), args.include)
144162
parser.run()
163+
145164
if parser.tests:
146165
exit_code = generate_robot_2_rst(parser, Path(args.rst_file), prefix, relationship_config,
147166
gen_matrix, test_type=test_type, only=args.expression, coverages=coverages)
@@ -154,6 +173,87 @@ def main():
154173
return exit_code
155174

156175

176+
def main():
177+
'''Main entry point for script: parse arguments and execute'''
178+
parser = argparse.ArgumentParser(
179+
description='Convert robot test cases to reStructuredText with traceable items.',
180+
formatter_class=argparse.RawTextHelpFormatter
181+
)
182+
parser.epilog = """
183+
examples:
184+
# Convert a file (default command)
185+
robot2rst -i input.robot -o output.rst
186+
187+
# Explicitly call convert
188+
robot2rst convert -i input.robot -o output.rst
189+
190+
# Check style of all .robot files in the current directory and subdirectories
191+
robot2rst stylecheck --fix
192+
"""
193+
subparsers = parser.add_subparsers(dest='command', help='Available commands')
194+
195+
# Conversion command
196+
parser_convert = subparsers.add_parser('convert', help='Converts a Robot Framework file to a reStructuredText '
197+
'(.rst) file (default).')
198+
parser_convert.add_argument("-i", "--robot", dest='robot_file', required=True,
199+
help='Input robot file')
200+
parser_convert.add_argument("-o", "--rst", dest='rst_file', required=True,
201+
help='Output RST file, e.g. my_component_qtp.rst')
202+
parser_convert.add_argument("--only", dest="expression", default="",
203+
help="Expression of tags for Sphinx' `only` directive that surrounds all RST content.")
204+
parser_convert.add_argument("-p", "--prefix", default='QTEST-',
205+
help="Overrides the default 'QTEST-' prefix.")
206+
parser_convert.add_argument("-r", "--relationships", nargs='*',
207+
help="Name(s) of the relationship(s) used to link to items in Tags section. "
208+
"Default: 'validates'.")
209+
parser_convert.add_argument("-t", "--tags", nargs='*',
210+
help="Python regexes for matching tags to treat as traceable targets. "
211+
"Matches all by default.")
212+
parser_convert.add_argument("--include", nargs='*', default=[],
213+
help="Python regexes for matching tags to filter test cases.")
214+
parser_convert.add_argument("-c", "--coverage", nargs='*',
215+
help="Minimum coverage percentages for the item-matrix(es); 1 value per tag in --tags.")
216+
parser_convert.add_argument("--type", default='q',
217+
help="Type of test ('q' for qualification, 'i' for integration). "
218+
"Default: 'qualification'.")
219+
parser_convert.add_argument("--trim-suffix", action='store_true',
220+
help="If the suffix of any prefix or --tags argument ends with '_-' it gets trimmed "
221+
"to '-'.")
222+
parser_convert.set_defaults(func=run_conversion)
223+
224+
# Stylecheck command
225+
parser_stylecheck = subparsers.add_parser('stylecheck',
226+
help='Checks and fixes RST style in Robot documentation blocks.')
227+
parser_stylecheck.add_argument('paths', nargs='*', default=['.'],
228+
help='One or more paths to files or folders to check. Default: current directory.')
229+
parser_stylecheck.add_argument("--fix", action="store_true",
230+
help="Automatically fix RST formatting inside Robot documentation blocks.")
231+
parser_stylecheck.add_argument("--fail-on-layout", action="store_true",
232+
help="Fail on RST layout issues as well as syntax issues.")
233+
parser_stylecheck.add_argument("--line-length", type=int, default=100,
234+
help="Max line length for RST blocks (note: the line length does not include the "
235+
"length of the [Documentation] tag for example). Default: 100.")
236+
parser_stylecheck.set_defaults(func=run_stylecheck)
237+
238+
# Make 'convert' the default command if no other command is specified
239+
commands = ['convert', 'stylecheck']
240+
help_flags = ['-h', '--help']
241+
is_command_present = any(cmd in sys.argv[1:2] for cmd in commands + help_flags)
242+
243+
if not is_command_present and len(sys.argv) > 1:
244+
sys.argv.insert(1, 'convert')
245+
246+
logging.basicConfig(level=logging.INFO)
247+
args = parser.parse_args()
248+
249+
if hasattr(args, 'func'):
250+
return args.func(args)
251+
else:
252+
# No command was given (e.g., `robot2rst` or `robot2rst --help`)
253+
parser.print_help()
254+
return 0
255+
256+
157257
def entrypoint():
158258
sys.exit(main())
159259

0 commit comments

Comments
 (0)