Skip to content

Commit a1129b5

Browse files
rjaegersgithub-actions[bot]Copilot
authored
feat: document generation (#946)
* chore: establish a basic structure for document generation * chore: playing around with location and granularity * chore: add gherkin extraction * docs: generate requirements document * fix: don't use sudo in workflows * fix: allow sudo in workflow that needs it * ci: install missing package * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Signed-off-by: Ron <[email protected]> * docs: generate nicer PDF * chore: correct workflow syntax * chore: minor refactor to workflow * chore: pin pip dependencies * docs: make the pdf more appealing * chore: refactor gherkin to sbdl workflow * chore: refactor requirement structure Allow for nested requirements, the top level being specified by the Feature name and description and child requirements being specified as Rules with their description. * chore: enable listings code highlighter * docs: add eisvogel front-matter * docs: update to front-matter config * docs: add more requirements * docs: add a toc * docs: extend requirements * chore: refactor gherkin to sbdl * Update docs/templates/software-requirements-specification.md.j2 Co-authored-by: Copilot <[email protected]> Signed-off-by: Ron <[email protected]> * chore: refactor for testability * chore: extend the urllib3 ignores with one month * chore: update linter settings We allow feature files without scenarios as we use the feature files as ground-truth for our requirements. As some requirements can be tested on a different level they have no associated scenario. * chore: add missing import * chore: add *.pyc to gitignore * chore: add documents to release upload * docs: minor cosmetic changes * chore: processed review comments * chore: correct/extend lychee scope * Update docs/support/gherkin_sbdl_converter.py Co-authored-by: Copilot <[email protected]> Signed-off-by: Ron <[email protected]> * Update .mega-linter.yml Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Signed-off-by: Ron <[email protected]> * style: add newline between classes --------- Signed-off-by: Ron <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <[email protected]>
1 parent 342e2b1 commit a1129b5

17 files changed

+555
-140
lines changed

.github/linters/.gherkin-lintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"no-duplicate-tags": "on",
88
"no-empty-background": "on",
99
"no-empty-file": "on",
10-
"no-files-without-scenarios": "on",
10+
"no-files-without-scenarios": "off",
1111
"no-multiple-empty-lines": "on",
1212
"no-partially-commented-tag-lines": "on",
1313
"no-scenario-outlines-without-examples": "on",

.github/workflows/release-build.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ jobs:
9090
GH_TOKEN: ${{ github.token }}
9191
REPOSITORY_OWNER: ${{ github.repository_owner }}
9292
REPOSITORY_NAME: ${{ github.event.repository.name }}
93+
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
94+
with:
95+
pattern: documents
96+
- name: Upload documents to release
97+
run: |
98+
set -Eeuo pipefail
99+
gh release upload "${REF_NAME}" ./*.pdf
100+
env:
101+
GH_REPO: ${{ github.repository }}
102+
GH_TOKEN: ${{ github.token }}
93103
- name: Update package details in release
94104
run: |
95105
set -Eeuo pipefail

.github/workflows/wc-document-generation.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,16 @@ jobs:
2222
set -Eeuo pipefail
2323
sudo apt-get update && sudo apt-get install --no-install-recommends -y plantuml
2424
python -m pip install gherkin-official==35.1.0 sbdl==1.16.4
25-
- name: Generate requirements document
25+
- name: Generate SRS document
2626
run: |
2727
set -Eeuo pipefail
28-
python docs/support/gherkin-to-csv.py test/cpp/features/*.feature
29-
python -m csv-to-sbdl --identifier 0 --description 1 --skipheader rules.csv
30-
sbdl -m template-fill --template docs/templates/requirements.template.md output.sbdl > requirements.md
28+
python docs/support/gherkin-to-sbdl.py test/cpp/features/*.feature
29+
sbdl -m template-fill --template docs/templates/software-requirements-specification.md.j2 output.sbdl > software-requirements-specification.md
3130
- uses: docker://pandoc/extra:3.7.0@sha256:a703d335fa237f8fc3303329d87e2555dca5187930da38bfa9010fa4e690933a
3231
with:
33-
args: --template eisvogel --output requirements.pdf requirements.md
32+
args: --template eisvogel --listings --number-sections --output software-requirements-specification.pdf software-requirements-specification.md
3433
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
3534
with:
3635
name: documents
37-
path: requirements.pdf
36+
path: "*.pdf"
3837
retention-days: 2

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ test-results/
1111
.env
1212
*.profdata
1313
*.profraw
14+
*.pyc
1415
**/playwright/.auth/user.json
1516
CMakeUserPresets.json

.mega-linter.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ ENABLE:
88
- SPELL
99
- YAML
1010
DISABLE_LINTERS:
11-
- MARKDOWN_MARKDOWN_LINK_CHECK
1211
- REPOSITORY_DEVSKIM
1312
- REPOSITORY_DUSTILOCK
1413
- REPOSITORY_KICS
@@ -18,6 +17,8 @@ DISABLE_LINTERS:
1817
SARIF_REPORTER: true
1918
PRINT_ALPACA: false
2019
SHOW_SKIPPED_LINTERS: false
20+
SPELL_LYCHEE_FILE_EXTENSIONS:
21+
[".feature", ".json", ".md", ".md.j2", ".txt", ".yaml", ".yml"]
2122
FILTER_REGEX_EXCLUDE: (CHANGELOG.md|package-lock.json)
2223
# tasks.json is wrongfully matched against another schema,
2324
# and schemas for .vscode/[tasks.json|launch.json] are built

docs/support/gherkin-to-csv.py

Lines changed: 0 additions & 75 deletions
This file was deleted.

docs/support/gherkin-to-sbdl.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import os
5+
import sys
6+
7+
from gherkin_mapping_config import FEATURE_RULE_CONFIG, FEATURE_RULE_SCENARIO_CONFIG
8+
from gherkin_sbdl_converter import GherkinConverter
9+
10+
def main():
11+
configs = {
12+
'feature-rule': FEATURE_RULE_CONFIG,
13+
'feature-rule-scenario': FEATURE_RULE_SCENARIO_CONFIG
14+
}
15+
16+
parser = argparse.ArgumentParser(description='Configurable Gherkin to SBDL converter')
17+
parser.add_argument('feature_files', nargs='+', help='Paths to feature files')
18+
parser.add_argument('--output', '-o', default='output.sbdl', help='Output SBDL file')
19+
parser.add_argument('--config', choices=configs.keys(),
20+
default='feature-rule', help='Conversion configuration preset')
21+
22+
args = parser.parse_args()
23+
config = configs[args.config]
24+
converter = GherkinConverter(config)
25+
gherkin_elements = []
26+
27+
for feature_path in args.feature_files:
28+
if os.path.isfile(feature_path):
29+
print(f"Processing {feature_path}")
30+
elements = converter.extract_from_feature_file(feature_path)
31+
gherkin_elements.extend(elements)
32+
else:
33+
print(f"File not found: {feature_path}", file=sys.stderr)
34+
35+
converter.write_sbdl_output(gherkin_elements, args.output)
36+
print(f"Extracted {len(gherkin_elements)} elements to {args.output}")
37+
38+
if __name__ == '__main__':
39+
main()
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Configuration-driven Gherkin to SBDL mapping with flexible hierarchy support.
5+
"""
6+
7+
from dataclasses import dataclass
8+
from typing import Dict, List, Optional, Union
9+
from enum import Enum
10+
11+
class GherkinElementType(Enum):
12+
"""Supported Gherkin element types for conversion."""
13+
FEATURE = "feature"
14+
RULE = "rule"
15+
SCENARIO = "scenario"
16+
SCENARIO_OUTLINE = "scenario_outline"
17+
EXAMPLE = "example"
18+
BACKGROUND = "background"
19+
20+
class SBDLElementType(Enum):
21+
"""Supported SBDL element types for mapping."""
22+
REQUIREMENT = "requirement"
23+
ASPECT = "aspect"
24+
USECASE = "usecase"
25+
DEFINITION = "definition"
26+
TEST = "test"
27+
28+
@dataclass
29+
class HierarchyMapping:
30+
"""Configuration for mapping Gherkin elements to SBDL with document hierarchy."""
31+
gherkin_type: GherkinElementType
32+
sbdl_type: SBDLElementType
33+
34+
@dataclass
35+
class ConversionConfig:
36+
"""Complete configuration for Gherkin to SBDL conversion."""
37+
hierarchy_mappings: List[HierarchyMapping]
38+
39+
def get_mapping_for_type(self, gherkin_type: GherkinElementType) -> Optional[HierarchyMapping]:
40+
"""Get the hierarchy mapping for a specific Gherkin element type."""
41+
for mapping in self.hierarchy_mappings:
42+
if mapping.gherkin_type == gherkin_type:
43+
return mapping
44+
return None
45+
46+
# Predefined configurations for different use cases
47+
48+
# Current Configuration (Feature -> Rule mapping)
49+
FEATURE_RULE_CONFIG = ConversionConfig(
50+
hierarchy_mappings=[
51+
HierarchyMapping(
52+
gherkin_type=GherkinElementType.FEATURE,
53+
sbdl_type=SBDLElementType.REQUIREMENT
54+
),
55+
HierarchyMapping(
56+
gherkin_type=GherkinElementType.RULE,
57+
sbdl_type=SBDLElementType.REQUIREMENT
58+
)
59+
]
60+
)
61+
62+
# Extended Configuration (Feature -> Rule -> Scenario mapping)
63+
FEATURE_RULE_SCENARIO_CONFIG = ConversionConfig(
64+
hierarchy_mappings=[
65+
HierarchyMapping(
66+
gherkin_type=GherkinElementType.FEATURE,
67+
sbdl_type=SBDLElementType.ASPECT
68+
),
69+
HierarchyMapping(
70+
gherkin_type=GherkinElementType.RULE,
71+
sbdl_type=SBDLElementType.REQUIREMENT
72+
),
73+
HierarchyMapping(
74+
gherkin_type=GherkinElementType.SCENARIO,
75+
sbdl_type=SBDLElementType.TEST
76+
)
77+
]
78+
)
79+
80+
# Flat Configuration (All as requirements at same level)
81+
FLAT_CONFIG = ConversionConfig(
82+
hierarchy_mappings=[
83+
HierarchyMapping(
84+
gherkin_type=GherkinElementType.FEATURE,
85+
sbdl_type=SBDLElementType.REQUIREMENT
86+
),
87+
HierarchyMapping(
88+
gherkin_type=GherkinElementType.RULE,
89+
sbdl_type=SBDLElementType.REQUIREMENT
90+
)
91+
]
92+
)
93+
94+
# Use Case Focused Configuration
95+
USECASE_CONFIG = ConversionConfig(
96+
hierarchy_mappings=[
97+
HierarchyMapping(
98+
gherkin_type=GherkinElementType.FEATURE,
99+
sbdl_type=SBDLElementType.USECASE
100+
),
101+
HierarchyMapping(
102+
gherkin_type=GherkinElementType.SCENARIO,
103+
sbdl_type=SBDLElementType.USECASE
104+
)
105+
]
106+
)

0 commit comments

Comments
 (0)