2.1: Requirements Management Systems
Overview
Requirements Management Systems (RMS) are the backbone of requirements engineering in ASPICE-compliant development. This section covers enterprise platforms, their capabilities, and AI-enhanced features for modern development.
Core RMS Capabilities
Essential Features Matrix
The following diagram maps the essential capabilities of a requirements management system, including traceability, baselining, change management, and reporting features required for ASPICE compliance.
Platform Comparison
Enterprise RMS Overview
| Platform | Vendor | Deployment | Primary Industries |
|---|---|---|---|
| IBM DOORS Next | IBM | Cloud/On-prem | Automotive, Aerospace, Defense |
| Jama Connect | Jama | Cloud/On-prem | Cross-industry, Medical |
| Polarion ALM | Siemens | Cloud/On-prem | Automotive, Medical |
| Codebeamer | PTC | Cloud/On-prem | Automotive, Rail |
| Helix RM | Perforce | Cloud/On-prem | Automotive, Aerospace |
| Visure | Visure | Cloud/On-prem | Defense, Aerospace |
Feature Comparison
Note: Feature ratings reflect capabilities as of Q4 2024. Verify current features with vendors as capabilities evolve rapidly, especially for AI features.
| Feature | DOORS | Jama | Polarion | Codebeamer | Helix RM |
|---|---|---|---|---|---|
| Rich Text Editing | Excellent | Excellent | Excellent | Good | Good |
| Custom Attributes | Excellent | Excellent | Excellent | Excellent | Excellent |
| Hierarchical Struct | Excellent | Good | Excellent | Excellent | Good |
| Trace Links | Excellent | Excellent | Excellent | Excellent | Excellent |
| Impact Analysis | Good | Excellent | Good | Excellent | Fair |
| Baseline Management | Excellent | Good | Excellent | Good | Excellent |
| Review Workflows | Good | Excellent | Excellent | Excellent | Fair |
| ReqIF Support | Excellent | Good | Excellent | Excellent | Good |
| OSLC Compliance | Excellent | Fair | Good | Fair | Fair |
| AI Features | Good | Good | Fair | Good | Limited |
| REST API | Good | Excellent | Good | Excellent | Good |
| Git Integration | Fair | Good | Excellent | Excellent | Excellent |
Legend: Excellent = Full support, Good = Strong support, Fair = Basic support, Limited = Minimal support
Traceability Architecture
Trace Link Model
The following diagram shows how the V-Model traceability chain flows through the RMS, connecting stakeholder needs through system and software requirements down to verification evidence. Each horizontal trace link enables impact analysis when requirements change.
Baseline Strategy
Baseline management preserves requirement snapshots at key project milestones. The baseline strategy diagram illustrates how progressive baselines support change control and audit readiness across the ASPICE assessment lifecycle.
RMS Configuration Example
Project Setup Script
"""
RMS Project Configuration Script
Sets up requirements structure for ASPICE compliance
"""
from dataclasses import dataclass
from typing import List, Dict
from enum import Enum
class RequirementType(Enum):
STAKEHOLDER = "STKH"
SYSTEM = "SYS"
SOFTWARE = "SWE"
HARDWARE = "HWE"
INTERFACE = "IFC"
SAFETY = "SAF"
SECURITY = "SEC"
class AttributeType(Enum):
STRING = "string"
ENUMERATION = "enumeration"
INTEGER = "integer"
DATE = "date"
USER = "user"
LINK = "link"
@dataclass
class RequirementAttribute:
"""Definition of a requirement attribute."""
name: str
attr_type: AttributeType
required: bool = False
values: List[str] = None # For enumeration type
class RMSProjectSetup:
"""Configure RMS project for ASPICE compliance."""
def __init__(self, project_name: str):
self.project_name = project_name
self.modules = []
self.attributes = []
self.link_types = []
def define_standard_attributes(self) -> List[RequirementAttribute]:
"""Define standard ASPICE-compliant attributes."""
return [
RequirementAttribute(
name="ID",
attr_type=AttributeType.STRING,
required=True
),
RequirementAttribute(
name="Text",
attr_type=AttributeType.STRING,
required=True
),
RequirementAttribute(
name="Rationale",
attr_type=AttributeType.STRING,
required=False
),
RequirementAttribute(
name="Status",
attr_type=AttributeType.ENUMERATION,
required=True,
values=["Draft", "In Review", "Approved", "Obsolete"]
),
RequirementAttribute(
name="Priority",
attr_type=AttributeType.ENUMERATION,
required=True,
values=["High", "Medium", "Low"]
),
RequirementAttribute(
name="Verification Method",
attr_type=AttributeType.ENUMERATION,
required=True,
values=["Test", "Analysis", "Review", "Demonstration"]
),
RequirementAttribute(
name="ASIL",
attr_type=AttributeType.ENUMERATION,
required=False,
values=["QM", "ASIL-A", "ASIL-B", "ASIL-C", "ASIL-D"]
),
RequirementAttribute(
name="Owner",
attr_type=AttributeType.USER,
required=True
),
RequirementAttribute(
name="Created Date",
attr_type=AttributeType.DATE,
required=True
),
RequirementAttribute(
name="Modified Date",
attr_type=AttributeType.DATE,
required=True
)
]
def define_module_structure(self) -> Dict[str, Dict]:
"""Define requirements module structure."""
return {
"01_Stakeholder_Requirements": {
"prefix": "STKH",
"type": RequirementType.STAKEHOLDER,
"parent": None,
"description": "Customer and stakeholder requirements"
},
"02_System_Requirements": {
"prefix": "SYS",
"type": RequirementType.SYSTEM,
"parent": "01_Stakeholder_Requirements",
"description": "System-level requirements"
},
"03_Software_Requirements": {
"prefix": "SWE",
"type": RequirementType.SOFTWARE,
"parent": "02_System_Requirements",
"description": "Software requirements specification"
},
"04_Hardware_Requirements": {
"prefix": "HWE",
"type": RequirementType.HARDWARE,
"parent": "02_System_Requirements",
"description": "Hardware requirements specification"
},
"05_Interface_Requirements": {
"prefix": "IFC",
"type": RequirementType.INTERFACE,
"parent": "02_System_Requirements",
"description": "Interface specifications"
},
"06_Safety_Requirements": {
"prefix": "SAF",
"type": RequirementType.SAFETY,
"parent": "02_System_Requirements",
"description": "Functional safety requirements"
},
"07_Security_Requirements": {
"prefix": "SEC",
"type": RequirementType.SECURITY,
"parent": "02_System_Requirements",
"description": "Cybersecurity requirements"
}
}
def define_link_types(self) -> List[Dict]:
"""Define traceability link types."""
return [
{
"name": "derives",
"source": "Parent Requirement",
"target": "Child Requirement",
"description": "Requirement decomposition"
},
{
"name": "satisfies",
"source": "Implementation",
"target": "Requirement",
"description": "Implementation satisfies requirement"
},
{
"name": "verifies",
"source": "Test Case",
"target": "Requirement",
"description": "Test verifies requirement"
},
{
"name": "allocates",
"source": "Requirement",
"target": "Architecture Element",
"description": "Requirement allocated to component"
},
{
"name": "refines",
"source": "Detail",
"target": "Abstract",
"description": "Refinement relationship"
},
{
"name": "conflicts",
"source": "Requirement",
"target": "Requirement",
"description": "Conflict between requirements"
},
{
"name": "depends",
"source": "Dependent",
"target": "Dependency",
"description": "Dependency relationship"
}
]
def generate_config(self) -> Dict:
"""Generate complete project configuration."""
return {
"project": {
"name": self.project_name,
"version": "1.0.0",
"standard": "ASPICE 4.0"
},
"attributes": [attr.__dict__ for attr in self.define_standard_attributes()],
"modules": self.define_module_structure(),
"link_types": self.define_link_types(),
"workflows": self._define_workflows(),
"reports": self._define_reports()
}
def _define_workflows(self) -> List[Dict]:
"""Define requirement workflows."""
return [
{
"name": "Standard Approval",
"states": ["Draft", "In Review", "Approved", "Obsolete"],
"transitions": [
{"from": "Draft", "to": "In Review", "action": "Submit for Review"},
{"from": "In Review", "to": "Approved", "action": "Approve"},
{"from": "In Review", "to": "Draft", "action": "Reject"},
{"from": "Approved", "to": "Obsolete", "action": "Deprecate"}
]
}
]
def _define_reports(self) -> List[Dict]:
"""Define standard reports."""
return [
{
"name": "Traceability Matrix",
"type": "matrix",
"rows": "Software Requirements",
"columns": "System Requirements",
"link_type": "derives"
},
{
"name": "Coverage Report",
"type": "coverage",
"source": "Requirements",
"target": "Test Cases",
"link_type": "verifies"
},
{
"name": "Requirements Status",
"type": "dashboard",
"metrics": ["Total", "Draft", "In Review", "Approved"]
}
]
# Usage
if __name__ == '__main__':
setup = RMSProjectSetup("BCM_Door_Lock_Controller")
config = setup.generate_config()
print(f"Project: {config['project']['name']}")
print(f"Modules: {len(config['modules'])}")
print(f"Attributes: {len(config['attributes'])}")
print(f"Link Types: {len(config['link_types'])}")
The following diagram compares the IBM DOORS product family, showing how DOORS Classic and DOORS Next Generation differ in architecture, deployment models, and integration capabilities.

---
## DOORS Next Configuration
### Project Area Setup
```yaml
# DOORS Next Project Area Configuration
# doors-project-config.yaml
project_area:
name: "BCM_Door_Lock_Controller"
description: "Body Control Module - Door Lock Requirements"
lifecycle: "ASPICE_Automotive"
process_configuration:
template: "ASPICE-4.1-Automotive"
iteration_type: "Milestone"
components:
- name: "Stakeholder Requirements"
abbreviation: "STKH"
owner: "product_manager"
- name: "System Requirements"
abbreviation: "SYS"
owner: "system_architect"
- name: "Software Requirements"
abbreviation: "SWE"
owner: "sw_architect"
- name: "Hardware Requirements"
abbreviation: "HWE"
owner: "hw_architect"
- name: "Safety Requirements"
abbreviation: "SAF"
owner: "safety_manager"
- name: "Security Requirements"
abbreviation: "SEC"
owner: "security_manager"
artifact_types:
- name: "Requirement"
attributes:
- name: "ID"
type: "string"
required: true
- name: "Title"
type: "string"
required: true
- name: "Description"
type: "rich_text"
required: true
- name: "Rationale"
type: "rich_text"
required: false
- name: "Status"
type: "enumeration"
values: ["Draft", "Proposed", "Approved", "Implemented", "Verified", "Deleted"]
required: true
- name: "Priority"
type: "enumeration"
values: ["Must Have", "Should Have", "Could Have", "Won't Have"]
required: true
- name: "Verification Method"
type: "enumeration"
values: ["Test", "Analysis", "Review", "Demonstration"]
required: true
- name: "ASIL"
type: "enumeration"
values: ["QM", "ASIL-A", "ASIL-B", "ASIL-C", "ASIL-D"]
required: false
link_types:
- name: "Satisfies"
source_type: "Requirement"
target_type: "Requirement"
direction: "forward"
- name: "Derives From"
source_type: "Requirement"
target_type: "Requirement"
direction: "backward"
- name: "Verified By"
source_type: "Requirement"
target_type: "Test Case"
direction: "forward"
- name: "Implements"
source_type: "Implementation"
target_type: "Requirement"
direction: "backward"
permissions:
roles:
- name: "Requirements Engineer"
permissions: ["create", "edit", "delete", "view", "export"]
- name: "Reviewer"
permissions: ["view", "comment", "approve"]
- name: "Viewer"
permissions: ["view", "export"]
- name: "Administrator"
permissions: ["all"]
baselines:
naming_convention: "{component}_{version}_{date}"
auto_baseline_triggers:
- on_approval_complete
- on_milestone_completion
reports:
- name: "Traceability Matrix"
type: "matrix"
format: ["html", "pdf", "excel"]
- name: "Requirements Status Dashboard"
type: "dashboard"
widgets:
- requirements_by_status
- requirements_by_priority
- trace_coverage
- name: "Impact Analysis"
type: "impact"
depth: 3
The following diagram illustrates Jama Connect's architecture, showing its REST API layer, project containers, item types, and integration points with external development tools.

### REST API Integration
```python
"""
Jama Connect REST API Client
For CI/CD integration and automation
"""
import requests
from typing import List, Dict, Optional
from dataclasses import dataclass
@dataclass
class JamaItem:
"""Jama item representation."""
id: int
global_id: str
item_type: str
fields: Dict
parent_id: Optional[int] = None
class JamaConnectClient:
"""Client for Jama Connect REST API."""
def __init__(self, base_url: str, client_id: str, client_secret: str):
self.base_url = base_url.rstrip('/')
self.auth = (client_id, client_secret)
self.session = requests.Session()
self.session.auth = self.auth
self.session.headers.update({
'Accept': 'application/json',
'Content-Type': 'application/json'
})
def get_projects(self) -> List[Dict]:
"""Get all projects."""
url = f"{self.base_url}/rest/latest/projects"
response = self.session.get(url)
response.raise_for_status()
return response.json().get('data', [])
def get_items(self, project_id: int, item_type: Optional[str] = None,
start_at: int = 0, max_results: int = 50) -> List[Dict]:
"""Get items from a project."""
url = f"{self.base_url}/rest/latest/items"
params = {
'project': project_id,
'startAt': start_at,
'maxResults': max_results
}
if item_type:
params['itemType'] = item_type
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json().get('data', [])
def get_item(self, item_id: int) -> Dict:
"""Get a specific item."""
url = f"{self.base_url}/rest/latest/items/{item_id}"
response = self.session.get(url)
response.raise_for_status()
return response.json().get('data', {})
def create_item(self, project_id: int, item_type_id: int,
fields: Dict, parent_id: Optional[int] = None) -> Dict:
"""Create a new item."""
url = f"{self.base_url}/rest/latest/items"
item_data = {
'project': project_id,
'itemType': item_type_id,
'fields': fields,
'location': {
'parent': {'item': parent_id} if parent_id else None
}
}
response = self.session.post(url, json=item_data)
response.raise_for_status()
return response.json().get('data', {})
def update_item(self, item_id: int, fields: Dict) -> Dict:
"""Update an item."""
url = f"{self.base_url}/rest/latest/items/{item_id}"
response = self.session.put(url, json={'fields': fields})
response.raise_for_status()
return response.json().get('data', {})
def get_relationships(self, item_id: int) -> List[Dict]:
"""Get relationships for an item."""
url = f"{self.base_url}/rest/latest/items/{item_id}/relationships"
response = self.session.get(url)
response.raise_for_status()
return response.json().get('data', [])
def create_relationship(self, from_item: int, to_item: int,
relationship_type: int) -> Dict:
"""Create a relationship between items."""
url = f"{self.base_url}/rest/latest/relationships"
rel_data = {
'fromItem': from_item,
'toItem': to_item,
'relationshipType': relationship_type
}
response = self.session.post(url, json=rel_data)
response.raise_for_status()
return response.json().get('data', {})
def get_baselines(self, project_id: int) -> List[Dict]:
"""Get baselines for a project."""
url = f"{self.base_url}/rest/latest/baselines"
params = {'project': project_id}
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json().get('data', [])
def create_baseline(self, project_id: int, name: str,
description: str) -> Dict:
"""Create a new baseline."""
url = f"{self.base_url}/rest/latest/baselines"
baseline_data = {
'project': project_id,
'name': name,
'description': description
}
response = self.session.post(url, json=baseline_data)
response.raise_for_status()
return response.json().get('data', {})
def get_item_types(self, project_id: int) -> List[Dict]:
"""Get item types for a project."""
url = f"{self.base_url}/rest/latest/itemtypes"
params = {'project': project_id}
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json().get('data', [])
def search_items(self, project_id: int, query: str) -> List[Dict]:
"""Search for items."""
url = f"{self.base_url}/rest/latest/abstractitems"
params = {
'project': project_id,
'contains': query
}
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json().get('data', [])
class JamaMetrics:
"""Calculate requirements metrics from Jama Connect."""
def __init__(self, client: JamaConnectClient):
self.client = client
def get_item_status_distribution(self, project_id: int) -> Dict:
"""Get item count by status."""
items = self.client.get_items(project_id, max_results=1000)
status_count = {}
for item in items:
status = item.get('fields', {}).get('status', 'Unknown')
status_count[status] = status_count.get(status, 0) + 1
return status_count
def get_trace_coverage(self, project_id: int,
source_type: str, target_type: str) -> Dict:
"""Calculate traceability coverage."""
source_items = self.client.get_items(
project_id, item_type=source_type, max_results=1000
)
total = len(source_items)
linked = 0
for item in source_items:
relationships = self.client.get_relationships(item['id'])
if any(r for r in relationships):
linked += 1
coverage = (linked / total * 100) if total > 0 else 0
return {
'total': total,
'linked': linked,
'coverage_percentage': round(coverage, 2)
}
# Usage
if __name__ == '__main__':
client = JamaConnectClient(
base_url='https://your-instance.jamacloud.com',
client_id='your-client-id',
client_secret='your-client-secret'
)
# Get projects
projects = client.get_projects()
print(f"Found {len(projects)} projects")
# Calculate metrics
metrics = JamaMetrics(client)
for project in projects[:3]:
status = metrics.get_item_status_distribution(project['id'])
print(f"Project {project['name']}: {status}")
Siemens Polarion
Configuration
# Polarion Project Configuration
# polarion-project.xml
project:
id: "BCM_Door_Lock"
name: "Body Control Module - Door Lock Controller"
description: "ASPICE-compliant requirements management"
work_item_types:
- id: "stakeholder_req"
name: "Stakeholder Requirement"
prefix: "STKH"
color: "#4CAF50"
- id: "system_req"
name: "System Requirement"
prefix: "SYS"
color: "#2196F3"
- id: "software_req"
name: "Software Requirement"
prefix: "SWE"
color: "#9C27B0"
- id: "test_case"
name: "Test Case"
prefix: "TC"
color: "#FF9800"
custom_fields:
- id: "rationale"
name: "Rationale"
type: "rich_text"
applicable_types: ["stakeholder_req", "system_req", "software_req"]
- id: "verification_method"
name: "Verification Method"
type: "enum"
values: ["Test", "Analysis", "Review", "Demonstration"]
applicable_types: ["system_req", "software_req"]
- id: "asil"
name: "ASIL"
type: "enum"
values: ["QM", "ASIL-A", "ASIL-B", "ASIL-C", "ASIL-D"]
applicable_types: ["system_req", "software_req"]
link_roles:
- id: "derives"
name: "Derives From"
opposite_role: "derived_by"
source_types: ["system_req", "software_req"]
target_types: ["stakeholder_req", "system_req"]
- id: "verifies"
name: "Verifies"
opposite_role: "verified_by"
source_types: ["test_case"]
target_types: ["system_req", "software_req"]
workflows:
- id: "req_workflow"
name: "Requirement Workflow"
applicable_types: ["stakeholder_req", "system_req", "software_req"]
states:
- id: "draft"
name: "Draft"
initial: true
- id: "in_review"
name: "In Review"
- id: "approved"
name: "Approved"
- id: "implemented"
name: "Implemented"
- id: "verified"
name: "Verified"
- id: "obsolete"
name: "Obsolete"
transitions:
- from: "draft"
to: "in_review"
action: "Submit for Review"
- from: "in_review"
to: "approved"
action: "Approve"
- from: "in_review"
to: "draft"
action: "Reject"
- from: "approved"
to: "implemented"
action: "Mark Implemented"
- from: "implemented"
to: "verified"
action: "Mark Verified"
- from: "*"
to: "obsolete"
action: "Obsolete"
conditions:
- "hasPermission('obsolete_items')"
documents:
- id: "srs_template"
name: "Software Requirements Specification"
template: "ASPICE_SRS_Template"
allowed_types: ["software_req"]
baselines:
naming_pattern: "{project}_{milestone}_{version}_{date}"
auto_create:
triggers:
- on_milestone_completion
- on_approval_gate
REST API Client
"""
Polarion REST API Client
For CI/CD integration and automation
"""
import requests
from zeep import Client
from zeep.transports import Transport
from typing import List, Dict, Optional
class PolarionClient:
"""Client for Polarion REST and SOAP APIs."""
def __init__(self, server_url: str, username: str, password: str):
self.server_url = server_url.rstrip('/')
self.username = username
self.password = password
self.session = self._create_session()
def _create_session(self) -> requests.Session:
"""Create authenticated session."""
session = requests.Session()
session.auth = (self.username, self.password)
session.headers.update({
'Accept': 'application/json',
'Content-Type': 'application/json'
})
return session
def get_projects(self) -> List[Dict]:
"""Get all projects."""
url = f"{self.server_url}/polarion/rest/v1/projects"
response = self.session.get(url)
response.raise_for_status()
return response.json().get('data', [])
def get_work_items(self, project_id: str, query: str = "",
page_size: int = 100) -> List[Dict]:
"""Get work items with optional query."""
url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems"
params = {
'query': query,
'page[size]': page_size
}
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json().get('data', [])
def get_work_item(self, project_id: str, work_item_id: str) -> Dict:
"""Get a specific work item."""
url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems/{work_item_id}"
response = self.session.get(url)
response.raise_for_status()
return response.json().get('data', {})
def create_work_item(self, project_id: str, work_item_type: str,
title: str, fields: Dict) -> Dict:
"""Create a new work item."""
url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems"
payload = {
'data': {
'type': 'workitems',
'attributes': {
'type': work_item_type,
'title': title,
**fields
}
}
}
response = self.session.post(url, json=payload)
response.raise_for_status()
return response.json().get('data', {})
def update_work_item(self, project_id: str, work_item_id: str,
fields: Dict) -> Dict:
"""Update a work item."""
url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems/{work_item_id}"
payload = {
'data': {
'type': 'workitems',
'id': f"{project_id}/{work_item_id}",
'attributes': fields
}
}
response = self.session.patch(url, json=payload)
response.raise_for_status()
return response.json().get('data', {})
def get_linked_work_items(self, project_id: str,
work_item_id: str) -> List[Dict]:
"""Get linked work items."""
url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems/{work_item_id}/linkedworkitems"
response = self.session.get(url)
response.raise_for_status()
return response.json().get('data', [])
def create_link(self, project_id: str, source_id: str,
target_id: str, role: str) -> bool:
"""Create a link between work items."""
url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/workitems/{source_id}/linkedworkitems"
payload = {
'data': [{
'type': 'linkedworkitems',
'attributes': {
'role': role,
'targetWorkItem': f"{project_id}/{target_id}"
}
}]
}
response = self.session.post(url, json=payload)
return response.status_code == 201
def get_documents(self, project_id: str) -> List[Dict]:
"""Get documents in a project."""
url = f"{self.server_url}/polarion/rest/v1/projects/{project_id}/spaces/_default/documents"
response = self.session.get(url)
response.raise_for_status()
return response.json().get('data', [])
def get_baselines(self, project_id: str) -> List[Dict]:
"""Get baselines for a project."""
# Query work items with baseline field
return self.get_work_items(project_id, "type:baseline")
def create_baseline(self, project_id: str, name: str,
description: str, work_item_ids: List[str]) -> Dict:
"""Create a baseline."""
# Polarion baselines are typically created via LiveDoc or SOAP API
# This is a simplified REST approach
pass
def run_query(self, project_id: str, lucene_query: str) -> List[Dict]:
"""Run a Lucene query."""
return self.get_work_items(project_id, lucene_query)
class PolarionMetrics:
"""Calculate requirements metrics from Polarion."""
def __init__(self, client: PolarionClient):
self.client = client
def get_status_distribution(self, project_id: str,
work_item_type: str) -> Dict:
"""Get work item count by status."""
items = self.client.get_work_items(
project_id, f"type:{work_item_type}"
)
status_count = {}
for item in items:
status = item.get('attributes', {}).get('status', 'Unknown')
status_count[status] = status_count.get(status, 0) + 1
return status_count
def get_trace_coverage(self, project_id: str,
source_type: str, link_role: str) -> Dict:
"""Calculate traceability coverage."""
source_items = self.client.get_work_items(
project_id, f"type:{source_type}"
)
total = len(source_items)
linked = 0
for item in source_items:
item_id = item.get('id', '').split('/')[-1]
links = self.client.get_linked_work_items(project_id, item_id)
# Check for links with specified role
if any(l.get('attributes', {}).get('role') == link_role
for l in links):
linked += 1
coverage = (linked / total * 100) if total > 0 else 0
return {
'total': total,
'linked': linked,
'coverage_percentage': round(coverage, 2)
}
# Usage
if __name__ == '__main__':
client = PolarionClient(
server_url='https://polarion-server.example.com',
username='api_user',
password='api_password'
)
# Get projects
projects = client.get_projects()
print(f"Found {len(projects)} projects")
# Search requirements
requirements = client.get_work_items(
'BCM_Door_Lock',
'type:software_req AND status:approved'
)
print(f"Found {len(requirements)} approved SW requirements")
PTC Codebeamer
Configuration
# Codebeamer Project Configuration
# codebeamer-config.yaml
project:
name: "BCM_Door_Lock_Controller"
description: "ASPICE-compliant requirements and ALM"
template: "ASPICE_Automotive"
trackers:
- name: "Stakeholder Requirements"
key: "STKH"
type: "requirement"
workflow: "requirement_workflow"
fields:
- name: "Description"
type: "wikitext"
mandatory: true
- name: "Rationale"
type: "wikitext"
- name: "Priority"
type: "choice"
options: ["Must Have", "Should Have", "Could Have", "Won't Have"]
- name: "System Requirements"
key: "SYS"
type: "requirement"
workflow: "requirement_workflow"
fields:
- name: "Description"
type: "wikitext"
mandatory: true
- name: "Verification Method"
type: "choice"
options: ["Test", "Analysis", "Review", "Demonstration"]
- name: "ASIL"
type: "choice"
options: ["QM", "ASIL-A", "ASIL-B", "ASIL-C", "ASIL-D"]
- name: "Software Requirements"
key: "SWE"
type: "requirement"
workflow: "requirement_workflow"
- name: "Test Cases"
key: "TC"
type: "testcase"
workflow: "testcase_workflow"
associations:
- name: "derives_from"
from_tracker: "System Requirements"
to_tracker: "Stakeholder Requirements"
propagate_suspect: true
- name: "derives_from"
from_tracker: "Software Requirements"
to_tracker: "System Requirements"
propagate_suspect: true
- name: "verifies"
from_tracker: "Test Cases"
to_tracker: "Software Requirements"
propagate_suspect: true
workflows:
requirement_workflow:
states:
- name: "Draft"
initial: true
- name: "In Review"
- name: "Approved"
- name: "Implemented"
- name: "Verified"
- name: "Obsolete"
final: true
transitions:
- from: "Draft"
to: "In Review"
permission: "requirement_submit"
- from: "In Review"
to: "Approved"
permission: "requirement_approve"
- from: "In Review"
to: "Draft"
permission: "requirement_reject"
baselines:
auto_create:
on_release: true
on_milestone: true
naming: "{project}_{tracker}_{version}_{date}"
integrations:
git:
enabled: true
repositories:
- url: "https://github.com/company/bcm-doorlock.git"
branch_pattern: "feature/*"
commit_association: true
jenkins:
enabled: true
server: "https://jenkins.example.com"
job_pattern: "BCM_*"
REST API Client
"""
PTC Codebeamer REST API Client
For CI/CD integration and automation
"""
import requests
from typing import List, Dict, Optional
from dataclasses import dataclass
@dataclass
class TrackerItem:
"""Codebeamer tracker item representation."""
id: int
name: str
tracker_id: int
status: str
description: str
custom_fields: Dict
class CodebeamerClient:
"""Client for Codebeamer REST API."""
def __init__(self, base_url: str, username: str, password: str):
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
self.session.auth = (username, password)
self.session.headers.update({
'Accept': 'application/json',
'Content-Type': 'application/json'
})
def get_projects(self) -> List[Dict]:
"""Get all projects."""
url = f"{self.base_url}/api/v3/projects"
response = self.session.get(url)
response.raise_for_status()
return response.json()
def get_trackers(self, project_id: int) -> List[Dict]:
"""Get trackers in a project."""
url = f"{self.base_url}/api/v3/projects/{project_id}/trackers"
response = self.session.get(url)
response.raise_for_status()
return response.json()
def get_tracker_items(self, tracker_id: int, page: int = 1,
page_size: int = 100,
query_string: str = "") -> Dict:
"""Get items from a tracker."""
url = f"{self.base_url}/api/v3/trackers/{tracker_id}/items"
params = {
'page': page,
'pageSize': page_size
}
if query_string:
params['queryString'] = query_string
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json()
def get_item(self, item_id: int) -> Dict:
"""Get a specific item."""
url = f"{self.base_url}/api/v3/items/{item_id}"
response = self.session.get(url)
response.raise_for_status()
return response.json()
def create_item(self, tracker_id: int, name: str,
description: str, fields: Dict = None) -> Dict:
"""Create a new tracker item."""
url = f"{self.base_url}/api/v3/trackers/{tracker_id}/items"
payload = {
'name': name,
'description': description,
**(fields or {})
}
response = self.session.post(url, json=payload)
response.raise_for_status()
return response.json()
def update_item(self, item_id: int, fields: Dict) -> Dict:
"""Update a tracker item."""
url = f"{self.base_url}/api/v3/items/{item_id}"
response = self.session.put(url, json=fields)
response.raise_for_status()
return response.json()
def get_associations(self, item_id: int) -> List[Dict]:
"""Get associations (links) for an item."""
url = f"{self.base_url}/api/v3/items/{item_id}/associations"
response = self.session.get(url)
response.raise_for_status()
return response.json()
def create_association(self, from_id: int, to_id: int,
association_type: str) -> Dict:
"""Create an association between items."""
url = f"{self.base_url}/api/v3/associations"
payload = {
'from': {'id': from_id},
'to': {'id': to_id},
'type': {'name': association_type}
}
response = self.session.post(url, json=payload)
response.raise_for_status()
return response.json()
def get_baselines(self, project_id: int) -> List[Dict]:
"""Get baselines for a project."""
url = f"{self.base_url}/api/v3/projects/{project_id}/baselines"
response = self.session.get(url)
response.raise_for_status()
return response.json()
def create_baseline(self, tracker_id: int, name: str,
description: str) -> Dict:
"""Create a baseline for a tracker."""
url = f"{self.base_url}/api/v3/trackers/{tracker_id}/baselines"
payload = {
'name': name,
'description': description
}
response = self.session.post(url, json=payload)
response.raise_for_status()
return response.json()
def run_cbql_query(self, query: str) -> List[Dict]:
"""Run a CBQL (Codebeamer Query Language) query."""
url = f"{self.base_url}/api/v3/items/query"
payload = {
'queryString': query,
'page': 1,
'pageSize': 500
}
response = self.session.post(url, json=payload)
response.raise_for_status()
return response.json().get('items', [])
def get_traceability_report(self, tracker_id: int,
downstream_tracker_id: int) -> Dict:
"""Get traceability report between trackers."""
url = f"{self.base_url}/api/v3/trackers/{tracker_id}/traceability"
params = {'downstreamTrackerId': downstream_tracker_id}
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json()
class CodebeamerMetrics:
"""Calculate requirements metrics from Codebeamer."""
def __init__(self, client: CodebeamerClient):
self.client = client
def get_status_distribution(self, tracker_id: int) -> Dict:
"""Get item count by status."""
result = self.client.get_tracker_items(tracker_id, page_size=1000)
items = result.get('items', [])
status_count = {}
for item in items:
status = item.get('status', {}).get('name', 'Unknown')
status_count[status] = status_count.get(status, 0) + 1
return status_count
def get_trace_coverage(self, source_tracker: int,
target_tracker: int) -> Dict:
"""Calculate traceability coverage."""
source_items = self.client.get_tracker_items(
source_tracker, page_size=1000
).get('items', [])
total = len(source_items)
linked = 0
for item in source_items:
associations = self.client.get_associations(item['id'])
# Check for associations to target tracker
if any(a.get('to', {}).get('tracker', {}).get('id') == target_tracker
for a in associations):
linked += 1
coverage = (linked / total * 100) if total > 0 else 0
return {
'total': total,
'linked': linked,
'coverage_percentage': round(coverage, 2)
}
def get_suspect_links(self, tracker_id: int) -> List[Dict]:
"""Get items with suspect links."""
query = f"tracker.id = {tracker_id} AND suspectLink = true"
return self.client.run_cbql_query(query)
# Usage
if __name__ == '__main__':
client = CodebeamerClient(
base_url='https://codebeamer.example.com/cb',
username='api_user',
password='api_password'
)
# Get projects
projects = client.get_projects()
print(f"Found {len(projects)} projects")
# Query requirements
requirements = client.run_cbql_query(
"tracker.name = 'Software Requirements' AND status = 'Approved'"
)
print(f"Found {len(requirements)} approved SW requirements")
# Check for suspect links
metrics = CodebeamerMetrics(client)
suspects = metrics.get_suspect_links(tracker_id=123)
print(f"Found {len(suspects)} items with suspect links")
CI/CD Integration
Unified Pipeline
// Jenkinsfile for multi-platform RMS integration
pipeline {
agent any
parameters {
choice(
name: 'RMS_PLATFORM',
choices: ['jama', 'polarion', 'codebeamer'],
description: 'Requirements Management System'
)
}
environment {
RMS_CREDENTIALS = credentials("${params.RMS_PLATFORM}-credentials")
}
stages {
stage('Requirements Validation') {
steps {
script {
def validator = load "scripts/${params.RMS_PLATFORM}_validator.groovy"
def result = validator.runQualityCheck(
server: env.RMS_SERVER,
project: env.PROJECT_NAME
)
if (result.failedCount > 0) {
unstable("${result.failedCount} requirements failed quality check")
}
}
}
}
stage('Traceability Check') {
steps {
script {
def checker = load "scripts/${params.RMS_PLATFORM}_trace.groovy"
def coverage = checker.getTraceCoverage(
server: env.RMS_SERVER,
project: env.PROJECT_NAME,
sourceType: 'Software Requirement',
targetType: 'Test Case'
)
echo "Trace coverage: ${coverage}%"
if (coverage < 95) {
unstable("Trace coverage ${coverage}% below 95% threshold")
}
}
}
}
stage('Export Requirements') {
when {
branch 'main'
}
steps {
script {
sh """
python3 scripts/rms_export.py \
--platform ${params.RMS_PLATFORM} \
--format reqif \
--output requirements.reqif
"""
archiveArtifacts 'requirements.reqif'
}
}
}
}
}
Summary
Jama, Polarion, Codebeamer Overview:
- Jama Connect: Modern UI, strong API, medical device focus
- Polarion: Full ALM, Siemens ecosystem, automotive strength
- Codebeamer: DevOps native, Git integration, agile support
- Common Features: Traceability, baselines, REST APIs
- Selection Factors: Industry focus, ecosystem fit, existing tools
Summary
Requirements Management Systems Overview:
- Core Capabilities: Capture, trace, baseline, report
- Enterprise Platforms: DOORS Next, Jama, Polarion, Codebeamer
- Integration Standards: ReqIF, OSLC, REST APIs
- AI Enhancement: NLP analysis, auto-tracing, quality metrics
- ASPICE Alignment: SYS.2, SWE.1, SUP.8, SUP.10