Skip to content

Commit

Permalink
docs: Add linter for the documentation (#2089)
Browse files Browse the repository at this point in the history
Add mdl as a linter for new cnf-testsuite documentation
Add custom rules for keeping format of the documentation
Add new git workflow with job lint to run mdl.

Signed-off-by: Konstantin Yarovoy <[email protected]>
  • Loading branch information
kosstennbl authored Jul 2, 2024
1 parent 2174f35 commit 8ef99b9
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 11 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ on:
paths:
- '**'
- '!**.md'
- '!docs/*'
- '!doc-lint/*'
pull_request:
paths:
- '**'
- '!**.md'
- '!docs/*'
- '!doc-lint/*'
jobs:
tests:
name: Fetch Matrix Tests
Expand Down
23 changes: 23 additions & 0 deletions .github/workflows/test-doc-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Test documentation lint
on:
push:
paths:
- 'docs/*'
- 'doc-lint/*'
pull_request:
paths:
- 'docs/*'
- 'doc-lint/*'
jobs:
lint-docs:
name: Lint Docs
runs-on: ubuntu-latest
container:
image: ruby:latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install mdl
run: gem install mdl
- name: Run mdl
run: mdl -s doc-lint/mdl-style.rb -u doc-lint/mdl-TTDS-rules.rb docs/TEST_DOCUMENTATION.md
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/docs/
/lib/
/utils/tar/lib/
/utils/tar/bin/
Expand Down
5 changes: 5 additions & 0 deletions doc-lint/Local-lint-usage
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Steps to run lint on TEST_DOCUMENTATION locally

- Install ruby version that suits your system https://www.ruby-lang.org/en/documentation/installation/
- Install MDL with gem package manager `gem install mdl` or build it from source https://github.com/markdownlint/markdownlint
- Run `mdl -s doc-lint/mdl-style.rb -u doc-lint/mdl-TTDS-rules.rb docs/TEST_DOCUMENTATION.md`, that should run Markdownlint with custom style and rules.
171 changes: 171 additions & 0 deletions doc-lint/mdl-TTDS-rules.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# TTDS stands for Testsuite Test Documentation Style
rule "TTDS001", "Testsuite documentation header format" do
tags :documentation
check do |doc|
parsed = doc.parsed
violation_lines = []
parsed.root.children.each do |element|
if element.type == :header
text = element.options[:raw_text]
line_number = element.options[:location]
case element.options[:level]
when 2
unless text == "Table of Contents" || text.start_with?("Category:")
violation_lines << line_number
end
when 4
allowed_texts = ["Overview", "Rationale", "Remediation", "Usage"]
unless allowed_texts.include?(text)
violation_lines << line_number
end
end
end
end
violation_lines.empty? ? nil : violation_lines
end
end

rule "TTDS002", "All categories and tests are present in TOC" do
tags :documentation
check do |doc|
toc_regex = /## Table of Contents\n\n[\s\S]*?\n## /m
doc_text = doc.lines.join("\n")
toc_text = doc_text.scan(toc_regex).first
parsed = doc.parsed
violation_lines = []
if toc_text.nil?
puts "Table of Contents not found"
violation_lines << 1
end
parsed.root.children.each do |element|
if element.type == :header
text = element.options[:raw_text]
line_number = element.options[:location]
case element.options[:level]
when 2
unless toc_text.include?(text)
violation_lines << line_number
end
when 3
unless text == "Usage" || toc_text.include?(text)
violation_lines << line_number
end
end
end
end
violation_lines.empty? ? nil : violation_lines
end
end

rule "TTDS003", "Separators before tests and categories are present" do
tags :documentation
check do |doc|
parsed = doc.parsed
violation_lines = []
parsed.root.children.each do |element|
if element.type == :header
text = element.options[:raw_text]
line_number = element.options[:location]
case element.options[:level]
when 2, 3
unless text == "Table of Contents" || text == "Usage"
separator_line_number = line_number - 3
separator_line = doc.lines[separator_line_number.clamp(0, doc.lines.length - 1)]
unless separator_line.strip =~ /---/
violation_lines << line_number
end
end
end
end
end
violation_lines.empty? ? nil : violation_lines
end
end

rule "TTDS004", "Tests should have all required sub-sections" do
tags :documentation
check do |doc|
parsed = doc.parsed
violation_lines = []
required_subsections = ["Overview", "Rationale", "Remediation", "Usage"]
current_test_header = nil
found_subsections = []
parsed.root.children.each do |element|
if element.type == :header
if element.options[:level] == 3 && element.options[:raw_text] != "Usage"
unless found_subsections.sort == required_subsections.sort || current_test_header.nil?
violation_lines << current_test_header.options[:location]
end
current_test_header = element
found_subsections = []
elsif element.options[:level] == 4
found_subsections << element.options[:raw_text]
end
end
end
unless found_subsections.sort == required_subsections.sort
violation_lines << current_test_header.options[:location]
end
violation_lines.empty? ? nil : violation_lines
end
end

rule "TTDS005", "TOC should not contain non-existent tests" do
tags :documentation
check do |doc|
toc_regex = /## Table of Contents\n\n[\s\S]*?\n## /m
doc_text = doc.lines.join("\n")
toc_text = doc_text.scan(toc_regex).first
parsed = doc.parsed
violation_lines = []
test_header_names = []
if toc_text.nil?
puts "Table of Contents not found"
violation_lines << 1
end
parsed.root.children.each do |element|
if element.type == :header
text = element.options[:raw_text]
line_number = element.options[:location]
if element.options[:level] == 3 && text != "Usage"
test_header_names << text.strip
end
end
end
toc_header_names = toc_text.scan(/\[\[([^\]]*)\]\]/).flatten
toc_header_names.each do |toc_header_name|
unless test_header_names.include?(toc_header_name)
violation_lines << 1
end
end
violation_lines.empty? ? nil : violation_lines
end
end

rule "TTDS006", "TOC should not contain 'dead' local links" do
tags :documentation
check do |doc|
parsed = doc.parsed
violation_lines = []
headers = Set[]
parsed.root.children.each do |element|
if element.type == :header
headers.add(element.options[:raw_text].downcase.delete('^a-z0-9\- ').tr(' ', '-'))
end
end
link_regex = /\[.*?\]\(#(.*?)\)/
doc.lines.each_with_index do |line, line_number|
match = line.scan(link_regex).flatten
if match
match.each do |link|
unless headers.include?(link)
violation_lines << line_number + 1
puts "Dead link: #{link}"
end
end

end
end
violation_lines.empty? ? nil : violation_lines
end
end
5 changes: 5 additions & 0 deletions doc-lint/mdl-style.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all
exclude_rule 'MD013' # Line length
exclude_rule 'MD024' # Multiple headers with the same content
exclude_rule 'MD057' # Table has missing or invalid header separation
exclude_rule 'MD055' # Table row doesn't begin/end with pipes
20 changes: 10 additions & 10 deletions docs/TEST_DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Table of Contents

* [**Category: Compatibility, Installability and Upgradability Tests**](#category-compatibility-installability--upgradability-tests)
* [**Category: Compatibility, Installability and Upgradability Tests**](#category-compatibility-installability-and-upgradability-tests)

[[Increase decrease capacity]](#increase-decrease-capacity) | [[Helm chart published]](#helm-chart-published) | [[Helm chart valid]](#helm-chart-valid) | [[Helm deploy]](#helm-deploy) | [[Rollback]](#rollback) | [[Rolling version change]](#rolling-version-change) | [[Rolling update]](#rolling-update) | [[Rolling downgrade]](#rolling-downgrade) | [[CNI compatible]](#cni-compatible) | [[Kubernetes Alpha APIs **PoC**]](#kubernetes-alpha-apis-poc)

Expand All @@ -14,11 +14,11 @@

[[Node drain]](#node-drain) | [[No local volume configuration]](#no-local-volume-configuration) | [[Elastic volumes]](#elastic-volumes) | [[Database persistence]](#database-persistence)

* [**Category: Reliability, Resilience and Availability Tests**](#category-reliability-resilience--availability-tests)
* [**Category: Reliability, Resilience and Availability Tests**](#category-reliability-resilience-and-availability-tests)

[[CNF under network latency]](#cnf-under-network-latency) | [[CNF with host disk fill]](#cnf-with-host-disk-fill) | [[Pod delete]](#pod-delete) | [[Memory hog]](#memory-hog) | [[IO Stress]](#io-stress) | [[Network corruption]](#network-corruption) | [[Network duplication]](#network-duplication) | [[Pod DNS errors]](#pod-dns-errors) | [[Helm chart liveness entry]](#helm-chart-liveness-entry) | [[Helm chart readiness entry]](#helm-chart-readiness-entry)

* [**Category: Observability and Diagnostic Tests**](#category-observability--diagnostic-tests)
* [**Category: Observability and Diagnostic Tests**](#category-observability-and-diagnostic-tests)

[[Use stdout/stderr for logs]](#use-stdoutstderr-for-logs) | [[Prometheus installed]](#prometheus-installed) | [[Routed logs]](#routed-logs) | [[OpenMetrics compatible]](#openmetrics-compatible) | [[Jaeger tracing]](#jaeger-tracing)

Expand All @@ -32,11 +32,11 @@

* [**Category: 5G Tests**](#category-5g-tests)

[[SMF_UPF_core_validator]](#smf_upf_core_validator) | [[SUCI_enabled]](#suci_enabled)
[[SMF UPF core validator]](#smf-upf-core-validator) | [[SUCI enabled]](#suci-enabled)

* [**Category: RAN Tests**](#category-ran-tests)

[[ORAN_e2_connection]](#oran_e2_connection)
[[ORAN e2 connection]](#oran-e2-connection)

* [**Category: Platform Tests**](#category-platform-tests)

Expand Down Expand Up @@ -1119,7 +1119,7 @@ Only connect PODs to the hostNetwork when it is necessary. If not, set the hostN
#### Overview

heck if the CNF is using service accounts that are automatically mapped.
Expectation: The [automatic mapping](https://bit.ly/C0034_service_account_mapping) of service account tokens should be disabled.
Expectation: The [automatic mapping](https://bit.ly/C0034_service_account_mapping) of service account tokens should be disabled.

#### Rationale

Expand Down Expand Up @@ -1315,7 +1315,7 @@ Set the filesystem of the container to read-only when possible. If the container

Checks the CNF's POD spec for any hostPath volumes, if found it checks the volume for the field mount.readOnly == false (or if it doesn’t exist).
Read more at [ARMO-C0045](https://bit.ly/3EvltIL)
Expectation: Containers should not have hostPath mounts
Expectation: Containers should not have hostPath mounts

#### Rationale

Expand Down Expand Up @@ -1552,7 +1552,7 @@ All 5G: `./cnf-testsuite 5g`

----------

### SMF_UPF_core_validator
### SMF UPF core validator

#### Overview

Expand All @@ -1572,7 +1572,7 @@ After measure a baseline of the heartbeat a comparison between the baseline and

----------

### SUCI_enabled
### SUCI enabled

#### Overview

Expand Down Expand Up @@ -1602,7 +1602,7 @@ ORAN cloud native functions should adhere to cloud native principles while also

----------

### ORAN_e2_connection
### ORAN e2 connection

#### Overview

Expand Down

0 comments on commit 8ef99b9

Please sign in to comment.