Skip to content

Commit bb4218c

Browse files
committed
version 1.1.0 introducing Requirements in a docs-as-code manner.
updated documentations and tests
1 parent cfe2bd8 commit bb4218c

23 files changed

+387
-67
lines changed

Examples_Reqs.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# `pumla` WeatherStation examples for requirements in docs-as-code style
2+
These are examples from the `./test/examples/WeatherStation` section. You find the
3+
source code of the .puml and .yaml files that form the example model repository
4+
there. In order to get the example running on your computer, you need
5+
to run first `pumla init`, then `pumla update`" in the examples directory,
6+
because the paths in the model repo file (./test/examples/WeatherStation/reqsrepo_json.puml)
7+
need to be updated to the directory structure on your computer. Currently
8+
the model repo file has the paths from the structure as I have it on my
9+
machine. You can't run the pumla update from the main path of pumla, as
10+
it is setup to update the architecture model repo of the pumla tool itself.
11+
The examples section will be ignored from the top level. So you have to go
12+
down to the examples and call the pumla update from that directory.
13+
14+
If you are changing the contents of the examples to play around, in order for a
15+
change to become alive, you need to call `pumla update` again. cd
16+
17+
## E#0: Creating Re-usable Requirements
18+
Other than with architecture elements, in `pumla` you write the requirements in YAML and not
19+
with PlantUML-conformant PUMLA-macros. Reason for that is, that requirements typically have
20+
more textual relevant information and a plain table structure with potentially quite a lot
21+
attributes that you want to have easy access on. Table-like data structures can be handled by PlantUML
22+
with JSON representations on diagrams. But when it comes to writing the text files, YAML is easier
23+
to use for requirements documentation than JSON. Therefore, `pumla` parses the YAML files and
24+
puts them into the requirements repository in JSON format, so that you can put the requirements
25+
easily onto diagrams.
26+
27+
See here an example for the definition of a re-usable requirement using by describing
28+
it in YAML:
29+
[./test/examples/WeatherStation/req.yaml](test/examples/WeatherStation/req.yaml)
30+
31+
```
32+
#PUMLARR
33+
- type: Requirement
34+
alias: REQ_WS1
35+
status: decided
36+
derived_from:
37+
taggedvalues:
38+
- tag: "Vendor"
39+
values:
40+
- A Inc.
41+
- C Ltd.
42+
- tag: "Variant"
43+
values: [SysA, SysB]
44+
content:
45+
This is a requirement towards my Weather Station. The Weather Station shall
46+
be able to measure the temperature.
47+
48+
- type: Requirement
49+
alias: REQ_WS2
50+
status: new
51+
derived_from:
52+
content:
53+
This is another requirement. The Weather Station housing shall be blue.
54+
55+
...
56+
```
57+
58+
59+
## E#1: Show all Requirements
60+
### E#1.1: All Requirements, full attributes, no trace
61+
See, how all requirements are put onto a diagram using the "`PUMLAPutAllReqs()`" macro for that
62+
purpose.
63+
64+
[./test/examples/WeatherStation/exampleAllReqs.puml](test/examples/WeatherStation/exampleAllReqs.puml)
65+
66+
![](test/examples/WeatherStation/pics/exampleAllReqs.png)
67+
68+
### E#1.2: All requirements, brief subset of attributes, showing the trace
69+
70+
### E#1.3: Overview of all requirements (Cheat Sheet)
71+
See here, how with one `pumla` macro `PUMLAPutAllReqsTable()` and overview table is put onto
72+
the diagram, counting the requirements and showing in which files they are implemented.
73+
74+
[./test/examples/WeatherStation/exampleReqCheatSheet.puml](test/examples/WeatherStation/exampleReqCheatSheet.puml)
75+
76+
![](test/examples/WeatherStation/pics/exampleReqCheatSheet.png)
77+
78+
## E#2: Put single requirements onto a diagram
79+
80+
## E#3: Show the requirements trace

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ Therefore, in order to enable systematic re-use for architecture models with Pla
2424
`pumla` is intended to be an extension around PlantUML to organize and enable
2525
this systematic re-use.
2626

27+
Furthermore, `pumla` now also supports requirements management in a docs-as-code manner. You can
28+
store your requirements in YAML text files in your git repo along with code and architecture, and
29+
also re-use the requirements definitions on diagrams, mixing it with architecture elements to show
30+
which element implements which requirement, but also create PlantUML diagrams showing a traceability
31+
graph.
32+
2733
### Goals, Use Cases & Principles
2834
<details>
2935
<summary>click to expand!</summary>
@@ -40,6 +46,8 @@ this systematic re-use.
4046
sequence diagrams with deployment diagrams.
4147
- Create an arc42 architecture documentation based on common PlantUML description patterns
4248
with almost no effort.
49+
- requirements in docs-as-code style that can be used in diagram explaining how they are implemented
50+
in the architecture
4351

4452
---
4553

@@ -209,6 +217,12 @@ to an overview and description an that example:
209217

210218
[follow this link to the C4 example](./test/examples/C4example/pumlaC4Example.md)
211219

220+
### Examples for managing and using requirements
221+
This is a set of examples showing how to use `pumla` for requirements management.
222+
223+
[follow this link to the requirements-as-code examples](./Examples_Reqs.md)
224+
225+
212226
### Working with the examples
213227
In order to play around with the previously mentioned examples, you need to initialise the examples
214228
repository to work on your system. To do that, take the following steps starting in the pumla

pumla_UsersGuide.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,12 @@ dynamic behaviour descriptions.
690690
Puts all the requirements of the requirements repository (`reqsrepo_json.puml`) onto the
691691
diagram, but only with the brief set of attributes (see `PUMLAPutReqBrief($alias)`).
692692

693+
## Working with Requirements Traceability
694+
### `PUMLAPutReqsBreakdownTraceFor($alias)`
695+
Puts the trace for a requirement with given alias down on the diagram. Each requirement along the
696+
trace is put with its brief description. The trace is modelled with a "realizes" relation, so pointing
697+
from a derived requirement to a parent requirement where it was derived from.
698+
693699
## Working around some PlantUML limitations
694700

695701
### `PUMLASetAsComponentDiagram()`

pumla_global_cfg.puml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@
3333
' interaction description).
3434
!$PUMC4UseDynamicExt = %false()
3535

36+
' max character width of requirements
37+
' conent attribute.
38+
!$PUMReqContentWidth = 15

pumla_macros_global.puml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
!$PUMLAVersionNumber = "v1.0.1"
1+
!$PUMLAVersionNumber = "v1.1.0"
22

33
!include pumla_internal.puml
44

pumla_macros_reqs.puml

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,141 @@
1+
@startuml
2+
3+
' ############################################
4+
' ---------------------------------------------
5+
' introduce "newline" into a List in order to
6+
' break it down after each colon
7+
!function formatListSL($text)
8+
!$result = ""
9+
!$index = 0
10+
!$text_length = %strlen($text)
11+
12+
!while ($index < $text_length)
13+
!$char = %substr($text, $index, 1)
14+
!$index = $index + 1
15+
16+
!if ($char == "[")
17+
!continue
18+
!endif
19+
20+
!if ($char == "]")
21+
!break
22+
!endif
23+
24+
!$result = $result + $char
25+
26+
!if ($char == ",")
27+
!$result = $result + "\n"
28+
!endif
29+
!endwhile
30+
31+
!return $result
32+
!endfunction
33+
34+
35+
36+
37+
' ############################################
38+
' ---------------------------------------------
39+
' introduce "newline" into a string in order to
40+
' break it down into several lines according
41+
' to a given char width of a line.
42+
!function _PUMLABreakLineNL($text)
43+
! $result = ""
44+
! $current_line = ""
45+
! $current_word = ""
46+
! $current_length = 0
47+
! $text_length = %strlen($text)
48+
! $index = 0
49+
50+
!while ($index < $text_length)
51+
! $char = %substr($text, $index, 1)
52+
! $index = $index + 1
53+
54+
!if ($char == " ")
55+
!if ($current_length + %strlen($current_word) > $PUMReqContentWidth)
56+
! $result = $result + $current_line + "%newline()"
57+
! $current_line = $current_word
58+
! $current_length = %strlen($current_word)
59+
!else
60+
!if ($current_length > 0)
61+
! $current_line = $current_line + " "
62+
! $current_length = $current_length + 1
63+
!endif
64+
! $current_line = $current_line + $current_word
65+
! $current_length = $current_length + %strlen($current_word)
66+
!endif
67+
! $current_word = ""
68+
!else
69+
! $current_word = $current_word + $char
70+
!endif
71+
!endwhile
72+
73+
!if (%strlen($current_word) > 0)
74+
!if ($current_length + %strlen($current_word) > $PUMReqContentWidth)
75+
! $result = $result + $current_line + "%newline()"
76+
! $current_line = $current_word
77+
!else
78+
!if ($current_length > 0)
79+
! $current_line = $current_line + " "
80+
!endif
81+
! $current_line = $current_line + $current_word
82+
!endif
83+
!endif
84+
85+
!return $result + $current_line
86+
!endfunction
87+
88+
' ############################################
89+
' ---------------------------------------------
90+
' introduce "\\" into a string in order to
91+
' break it down into several lines according
92+
' to a given char width of a line.
93+
!function _PUMLABreakLineSL($text)
94+
! $result = ""
95+
! $current_line = ""
96+
! $current_word = ""
97+
! $current_length = 0
98+
! $text_length = %strlen($text)
99+
! $index = 0
100+
101+
!while ($index < $text_length)
102+
! $char = %substr($text, $index, 1)
103+
! $index = $index + 1
104+
105+
!if ($char == " ")
106+
!if ($current_length + %strlen($current_word) > $PUMReqContentWidth)
107+
! $result = $result + $current_line + " \n "
108+
! $current_line = $current_word
109+
! $current_length = %strlen($current_word)
110+
!else
111+
!if ($current_length > 0)
112+
! $current_line = $current_line + " "
113+
! $current_length = $current_length + 1
114+
!endif
115+
! $current_line = $current_line + $current_word
116+
! $current_length = $current_length + %strlen($current_word)
117+
!endif
118+
! $current_word = ""
119+
!else
120+
! $current_word = $current_word + $char
121+
!endif
122+
!endwhile
123+
124+
!if (%strlen($current_word) > 0)
125+
!if ($current_length + %strlen($current_word) > $PUMReqContentWidth)
126+
! $result = $result + $current_line + " \n "
127+
! $current_line = $current_word
128+
!else
129+
!if ($current_length > 0)
130+
! $current_line = $current_line + " "
131+
!endif
132+
! $current_line = $current_line + $current_word
133+
!endif
134+
!endif
135+
136+
!return $result + $current_line
137+
!endfunction
138+
1139
' ############################################
2140
' ---------------------------------------------
3141
' create a req as an object with reduced number
@@ -12,7 +150,7 @@
12150
' the $r object should not be possible here...
13151
object $r.alias {
14152
|= type | $r.type |
15-
|= content | $r.content |
153+
|= content | _PUMLABreakLineSL($r.content) |
16154
|= status | $r.status |
17155
}
18156
%set_variable_value($robjid, "%true()")
@@ -100,6 +238,7 @@ PUMLAPutElementErrorCheck($int_suc, $alias)
100238
!$cntall=$cntall+1
101239
!if $count == $cntall
102240
!$int_suc = %true()
241+
!$r.content = _PUMLABreakLineSL($r.content)
103242
json $r.alias $r
104243
!endif
105244
!endfor
@@ -125,7 +264,7 @@ note as allreqstable
125264
!foreach $r in $allreqs.reqs
126265
!$cntall=$cntall+1
127266
| | | | | | | |
128-
| $cntall | $r.alias | $r.type | $r.content | $r.status | $r.derived_from | $r.derived_to | $r.in_file |
267+
| $cntall | $r.alias | $r.type | _PUMLABreakLineSL($r.content) | $r.status | formatListSL($r.derived_from) | formatListSL($r.derived_to) | $r.in_file |
129268
!endfor
130269

131270
A total of $cntall requirements.

reqs_json_diagram.puml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@startjson
2+
{"reqsrepopath": "/Users/mvoss/Desktop/test/examples/WeatherStation", "reqsrepofile": "reqsrepo_json.puml", "reqs": []}
3+
@endjson
4+
5+

reqsrepo_json.puml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
!$allreqs = {"reqsrepopath": "/Users/mvoss/Desktop/test/examples/WeatherStation", "reqsrepofile": "reqsrepo_json.puml", "reqs": []}
2+

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = pumla
3-
version = 1.0.1
3+
version = 1.1.0
44
description = Command Line Tool for the PlantUML extension to enable architecture element re-usability.
55
long_description = file: README.md
66
license = GPL-3.0-only

src/pumla/control/reqparse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def updatePUMLAReqRepo(path, mrefilename):
8181
# make it accessible from within PlantUML.
8282
# $allreqs is the preprocessor variable that
8383
# allows access by PlantUML pumla marcros.
84-
pumlareqdict = {"reqsrepopath": path, "reqsrepofile": mrefilename, "reqs": pumlareqslist}
84+
pumlareqdict = {"reqsrepopath": os.path.abspath(path), "reqsrepofile": mrefilename, "reqs": pumlareqslist}
8585
reqjsontxt = json.dumps(pumlareqdict)
8686
jsontxt = "!$allreqs = " + reqjsontxt
8787

0 commit comments

Comments
 (0)