Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(anta): Add Markdown report option to ANTA #740

Merged
merged 29 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c5c517a
feat(anta): Add markdown report option to ANTA CLI
carl-baillargeon Jul 4, 2024
ef3a942
Update MDReportFactory
carl-baillargeon Jul 4, 2024
7920718
Make Py3.11 happy with f-string
carl-baillargeon Jul 4, 2024
0c1e957
Remove unnecessary only_failed_tests from MDReportBase
carl-baillargeon Jul 4, 2024
cb35a83
Added TestStats
carl-baillargeon Jul 8, 2024
733c159
Fix typos
carl-baillargeon Jul 8, 2024
aa2168f
Fix pytest
carl-baillargeon Jul 8, 2024
e72b22a
Added unit tests for reporter and result_manager
carl-baillargeon Jul 9, 2024
874467b
Added unit tests for md_reporter
carl-baillargeon Jul 9, 2024
650b8e2
Fix unit tests for md_reporter
carl-baillargeon Jul 9, 2024
230bd0a
Remove license from test md reports
carl-baillargeon Jul 9, 2024
8410064
Fix line too long
carl-baillargeon Jul 9, 2024
1747500
Added more unit tests
carl-baillargeon Jul 9, 2024
f34b1fe
Added documentation
carl-baillargeon Jul 9, 2024
596d029
Remove test.md
carl-baillargeon Jul 9, 2024
30c8d7e
Address review comments
carl-baillargeon Jul 11, 2024
73208a5
Update unit tests for ResultManager
carl-baillargeon Jul 11, 2024
8d14307
More unit tests
carl-baillargeon Jul 11, 2024
57f2021
Merge branch 'main' into feat/md_report
gmuloc Jul 12, 2024
fb2139a
Reduce number of tests in fake reports
carl-baillargeon Jul 18, 2024
d217ac3
Fix per review comments
carl-baillargeon Jul 18, 2024
5c44994
Rebase with latest main
carl-baillargeon Jul 18, 2024
16ae28c
Remove unrelated changes
carl-baillargeon Jul 18, 2024
dc23513
Merge branch 'main' into feat/md_report
carl-baillargeon Aug 19, 2024
8918cd0
Fix per review comments
carl-baillargeon Aug 19, 2024
7abf73a
Merge branch 'main' into feat/md_report
carl-baillargeon Aug 19, 2024
83d8602
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 19, 2024
21cb559
Merge branch 'main' into feat/md_report
gmuloc Aug 29, 2024
8372826
Added unit test for --hide
carl-baillargeon Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ repos:
- name: Check and insert license on Markdown files
id: insert-license
files: .*\.md$
# exclude:
exclude: ^tests/data/.*\.md$
args:
- --license-filepath
- .github/license-short.txt
Expand Down
1 change: 1 addition & 0 deletions anta/cli/nrfu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,4 @@ def nrfu(
nrfu.add_command(commands.json)
nrfu.add_command(commands.text)
nrfu.add_command(commands.tpl_report)
nrfu.add_command(commands.md_report)
24 changes: 20 additions & 4 deletions anta/cli/nrfu/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from anta.cli.utils import exit_with_code

from .utils import print_jinja, print_json, print_table, print_text, run_tests, save_to_csv
from .utils import print_jinja, print_json, print_table, print_text, run_tests, save_markdown_report, save_to_csv

logger = logging.getLogger(__name__)

Expand All @@ -28,7 +28,7 @@
required=False,
)
def table(ctx: click.Context, group_by: Literal["device", "test"] | None) -> None:
"""ANTA command to check network states with table result."""
"""ANTA command to check network state with table results."""
run_tests(ctx)
print_table(ctx, group_by=group_by)
exit_with_code(ctx)
Expand All @@ -45,7 +45,7 @@ def table(ctx: click.Context, group_by: Literal["device", "test"] | None) -> Non
help="Path to save report as a JSON file",
)
def json(ctx: click.Context, output: pathlib.Path | None) -> None:
"""ANTA command to check network state with JSON result."""
"""ANTA command to check network state with JSON results."""
run_tests(ctx)
print_json(ctx, output=output)
exit_with_code(ctx)
Expand All @@ -54,7 +54,7 @@ def json(ctx: click.Context, output: pathlib.Path | None) -> None:
@click.command()
@click.pass_context
def text(ctx: click.Context) -> None:
"""ANTA command to check network states with text result."""
"""ANTA command to check network state with text results."""
run_tests(ctx)
print_text(ctx)
exit_with_code(ctx)
Expand Down Expand Up @@ -105,3 +105,19 @@ def tpl_report(ctx: click.Context, template: pathlib.Path, output: pathlib.Path
run_tests(ctx)
print_jinja(results=ctx.obj["result_manager"], template=template, output=output)
exit_with_code(ctx)


@click.command()
@click.pass_context
@click.option(
"--md-output",
type=click.Path(file_okay=True, dir_okay=False, exists=False, writable=True, path_type=pathlib.Path),
show_envvar=True,
required=True,
help="Path to save the report as a Markdown file",
)
def md_report(ctx: click.Context, md_output: pathlib.Path) -> None:
"""ANTA command to check network state with Markdown report."""
run_tests(ctx)
save_markdown_report(ctx, md_output=md_output)
exit_with_code(ctx)
17 changes: 17 additions & 0 deletions anta/cli/nrfu/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from anta.models import AntaTest
from anta.reporter import ReportJinja, ReportTable
from anta.reporter.csv_reporter import ReportCsv
from anta.reporter.md_reporter import MDReportGenerator
from anta.runner import main

if TYPE_CHECKING:
Expand Down Expand Up @@ -141,6 +142,22 @@ def save_to_csv(ctx: click.Context, csv_file: pathlib.Path) -> None:
ctx.exit(ExitCode.USAGE_ERROR)


def save_markdown_report(ctx: click.Context, md_output: pathlib.Path) -> None:
"""Save the markdown report to a file.

Parameters
----------
ctx: Click context containing the result manager.
md_output: Path to save the markdown report.
"""
try:
MDReportGenerator.generate(results=_get_result_manager(ctx), md_filename=md_output)
console.print(f"Markdown report saved to {md_output} ✅", style="cyan")
except OSError:
console.print(f"Failed to save Markdown report to {md_output} ❌", style="cyan")
ctx.exit(ExitCode.USAGE_ERROR)


# Adding our own ANTA spinner - overriding rich SPINNERS for our own
# so ignore warning for redefinition
rich.spinner.SPINNERS = { # type: ignore[attr-defined]
Expand Down
19 changes: 19 additions & 0 deletions anta/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
"""Constants used in ANTA."""

from __future__ import annotations

ACRONYM_CATEGORIES: set[str] = {"aaa", "mlag", "snmp", "bgp", "ospf", "vxlan", "stp", "igmp", "ip", "lldp", "ntp", "bfd", "ptp", "lanz", "stun", "vlan"}
"""A set of network protocol or feature acronyms that should be represented in uppercase."""

MD_REPORT_TOC = """**Table of Contents:**

- [ANTA Report](#anta-report)
- [Test Results Summary](#test-results-summary)
- [Summary Totals](#summary-totals)
- [Summary Totals Device Under Test](#summary-totals-device-under-test)
- [Summary Totals Per Category](#summary-totals-per-category)
- [Test Results](#test-results)"""
"""Table of Contents for the Markdown report."""
36 changes: 12 additions & 24 deletions anta/reporter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,21 +154,15 @@ def report_summary_tests(
self.Headers.list_of_error_nodes,
]
table = self._build_headers(headers=headers, table=table)
for test in manager.get_tests():
for test, stats in sorted(manager.test_stats.items()):
if tests is None or test in tests:
results = manager.filter_by_tests({test}).results
nb_failure = len([result for result in results if result.result == "failure"])
nb_error = len([result for result in results if result.result == "error"])
list_failure = [result.name for result in results if result.result in ["failure", "error"]]
nb_success = len([result for result in results if result.result == "success"])
nb_skipped = len([result for result in results if result.result == "skipped"])
table.add_row(
test,
str(nb_success),
str(nb_skipped),
str(nb_failure),
str(nb_error),
str(list_failure),
str(stats.devices_success_count),
str(stats.devices_skipped_count),
str(stats.devices_failure_count),
str(stats.devices_error_count),
", ".join(stats.devices_failure),
)
return table

Expand Down Expand Up @@ -202,21 +196,15 @@ def report_summary_devices(
self.Headers.list_of_error_tests,
]
table = self._build_headers(headers=headers, table=table)
for device in manager.get_devices():
for device, stats in sorted(manager.device_stats.items()):
if devices is None or device in devices:
results = manager.filter_by_devices({device}).results
nb_failure = len([result for result in results if result.result == "failure"])
nb_error = len([result for result in results if result.result == "error"])
list_failure = [result.test for result in results if result.result in ["failure", "error"]]
nb_success = len([result for result in results if result.result == "success"])
nb_skipped = len([result for result in results if result.result == "skipped"])
table.add_row(
device,
str(nb_success),
str(nb_skipped),
str(nb_failure),
str(nb_error),
str(list_failure),
str(stats.tests_success_count),
str(stats.tests_skipped_count),
str(stats.tests_failure_count),
str(stats.tests_error_count),
", ".join(stats.tests_failure),
)
return table

Expand Down
Loading
Loading