Skip to content

Commit 2ca3c15

Browse files
committed
fix filegroups in architectural design
1 parent 41d3bf2 commit 2ca3c15

5 files changed

Lines changed: 173 additions & 7 deletions

File tree

bazel/rules/rules_score/private/architectural_design.bzl

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,34 @@ def _parse_puml_diagrams(ctx, files):
8787
lobster_outputs.append(lobster)
8888
return fbs_outputs, lobster_outputs
8989

90+
# Allowed file extensions per attribute.
91+
# static/dynamic: diagram sources (.puml/.plantuml) and documentation (.rst/.md).
92+
# public_api: diagram sources only — lobster traceability requires parseable diagrams.
93+
_ALLOWED_EXTENSIONS = {
94+
"static": ["puml", "plantuml", "rst", "md"],
95+
"dynamic": ["puml", "plantuml", "rst", "md"],
96+
"public_api": ["puml", "plantuml"],
97+
}
98+
99+
def _validate_file_extensions(ctx):
100+
"""Fail early if any resolved file has an unsupported extension.
101+
102+
Works for both direct file labels and filegroup contents because
103+
ctx.files.* flattens everything to individual File objects.
104+
"""
105+
for attr_name, allowed in _ALLOWED_EXTENSIONS.items():
106+
for f in getattr(ctx.files, attr_name):
107+
if f.extension not in allowed:
108+
fail(
109+
"File '{}' passed to attribute '{}' of target '{}' has " +
110+
"unsupported extension '.{}'. Allowed extensions: {}",
111+
f.short_path,
112+
attr_name,
113+
ctx.label,
114+
f.extension,
115+
[".{}".format(e) for e in allowed],
116+
)
117+
90118
def _architectural_design_impl(ctx):
91119
"""Implementation for architectural_design rule.
92120
@@ -104,6 +132,8 @@ def _architectural_design_impl(ctx):
104132
List of providers including DefaultInfo, ArchitecturalDesignInfo, SphinxSourcesInfo
105133
"""
106134

135+
_validate_file_extensions(ctx)
136+
107137
# Parse static and dynamic diagrams separately so each provider field
108138
# carries the flatbuffers for its own category
109139
static_fbs_list, static_lobster_list = _parse_puml_diagrams(ctx, ctx.files.static)
@@ -172,17 +202,17 @@ _architectural_design = rule(
172202
"Automatically parses PlantUML files to produce FlatBuffers binary representations.",
173203
attrs = {
174204
"static": attr.label_list(
175-
allow_files = [".puml", ".plantuml", ".svg", ".rst", ".md"],
205+
allow_files = True,
176206
mandatory = False,
177-
doc = "Static architecture diagrams (class diagrams, component diagrams, etc.)",
207+
doc = "Static architecture diagrams. Accepts direct file labels, filegroups, or any target whose files include .puml/.plantuml (parsed to FlatBuffers) or .rst/.md (documentation).",
178208
),
179209
"dynamic": attr.label_list(
180-
allow_files = [".puml", ".plantuml", ".svg", ".rst", ".md"],
210+
allow_files = True,
181211
mandatory = False,
182-
doc = "Dynamic architecture diagrams (sequence diagrams, activity diagrams, etc.)",
212+
doc = "Dynamic architecture diagrams. Accepts direct file labels, filegroups, or any target whose files include .puml/.plantuml (parsed to FlatBuffers) or .rst/.md (documentation).",
183213
),
184214
"public_api": attr.label_list(
185-
allow_files = [".puml", ".plantuml"],
215+
allow_files = True,
186216
mandatory = False,
187217
doc = "Public API diagrams (parsed identically to static/dynamic). " +
188218
"Classified separately so their lobster items are exposed via " +
@@ -213,7 +243,8 @@ def architectural_design(
213243
static = [],
214244
dynamic = [],
215245
public_api = [],
216-
visibility = None):
246+
visibility = None,
247+
tags = []):
217248
"""Define architectural design following S-CORE process guidelines.
218249
219250
Architectural design documents describe the software architecture of a
@@ -237,6 +268,7 @@ def architectural_design(
237268
diagrams but classified separately so their lobster items are
238269
exposed via public_api_lobster_files, enabling failure-mode-to-
239270
interface traceability at the dependable element level.
271+
tags: List of Bazel tags to apply to the generated target.
240272
visibility: Bazel visibility specification for the generated targets.
241273
242274
Generated Targets:
@@ -265,4 +297,5 @@ def architectural_design(
265297
dynamic = dynamic,
266298
public_api = public_api,
267299
visibility = visibility,
300+
tags = tags,
268301
)

bazel/rules/rules_score/private/dependable_element.bzl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,8 @@ _dependable_element_index = rule(
987987
),
988988
"architectural_design": attr.label_list(
989989
mandatory = True,
990-
doc = "Architectural design targets or files.",
990+
providers = [ArchitecturalDesignInfo],
991+
doc = "Architectural design targets (architectural_design rule only).",
991992
),
992993
"dependability_analysis": attr.label_list(
993994
mandatory = True,

bazel/rules/rules_score/test/BUILD

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ load(
6868
)
6969
load(
7070
":seooc_test.bzl",
71+
"arch_design_invalid_extension_test",
7172
"seooc_artifacts_copied_test",
7273
"seooc_description_test",
74+
"seooc_filegroup_arch_design_test",
7375
"seooc_index_generation_test",
7476
"seooc_needs_provider_test",
7577
"seooc_sphinx_module_generated_test",
@@ -183,6 +185,31 @@ architectural_design(
183185
static = ["fixtures/test_dependable_element_nested.puml"],
184186
)
185187

188+
# Filegroup fixture: a plain RST file wrapped in a filegroup, used to test
189+
# that architectural_design.static accepts filegroup targets (not just direct file labels).
190+
filegroup(
191+
name = "static_arch_filegroup",
192+
srcs = ["fixtures/seooc_test/static_architecture.rst"],
193+
)
194+
195+
# architectural_design that mixes a filegroup (RST docs) and a direct .puml file.
196+
# The .puml provides the SEooC declaration with no components (matching components=[]);
197+
# the filegroup exercises filegroup support.
198+
architectural_design(
199+
name = "arch_design_with_filegroup",
200+
static = [
201+
":static_arch_filegroup",
202+
"fixtures/test_de_filegroup_arch_design.puml",
203+
],
204+
)
205+
206+
# Filegroup with an unsupported file extension (.cc) — used by the failure test
207+
# that verifies architectural_design rejects bad file types at analysis time.
208+
filegroup(
209+
name = "invalid_ext_filegroup",
210+
srcs = ["fixtures/mock_lib1.cc"],
211+
)
212+
186213
# - Safety Analysis (DFA): wp__sw_component_dfa
187214
# - Safety Analysis (FMEA): wp__sw_component_fmea
188215
dependability_analysis(
@@ -414,6 +441,21 @@ dependable_element(
414441
tests = [],
415442
)
416443

444+
# Dependable element that passes a filegroup into architectural_design via a wrapper
445+
# architectural_design target. Exercises the filegroup-in-static path.
446+
dependable_element(
447+
name = "test_de_filegroup_arch_design",
448+
testonly = True,
449+
architectural_design = [":arch_design_with_filegroup"],
450+
assumptions_of_use = [":aous"],
451+
components = [],
452+
dependability_analysis = [":dependability_analysis_target"],
453+
description = "Test dependable element using a filegroup inside architectural_design.",
454+
integrity_level = "B",
455+
requirements = [":feat_req"],
456+
tests = [],
457+
)
458+
417459
# ============================================================================
418460
# Test Instantiations - HTML Generation Tests
419461
# ============================================================================
@@ -506,6 +548,24 @@ seooc_description_test(
506548
target_under_test = ":seooc_test_lib_index",
507549
)
508550

551+
seooc_filegroup_arch_design_test(
552+
name = "seooc_filegroup_arch_design_test",
553+
target_under_test = ":test_de_filegroup_arch_design_index",
554+
)
555+
556+
# Failure test: architectural_design must reject files with unsupported extensions
557+
# even when they arrive via a filegroup.
558+
architectural_design(
559+
name = "arch_design_invalid_ext",
560+
static = [":invalid_ext_filegroup"],
561+
tags = ["manual"],
562+
)
563+
564+
arch_design_invalid_extension_test(
565+
name = "arch_design_invalid_extension_test",
566+
target_under_test = ":arch_design_invalid_ext",
567+
)
568+
509569
# ============================================================================
510570
# Test Suites
511571
# ============================================================================
@@ -570,6 +630,8 @@ sphinx_module_providers_test_suite(name = "sphinx_module_providers_tests")
570630
test_suite(
571631
name = "seooc_tests",
572632
tests = [
633+
":arch_design_invalid_extension_test",
634+
":seooc_filegroup_arch_design_test",
573635
":seooc_tests_artifacts_copied",
574636
":seooc_tests_description",
575637
":seooc_tests_index_generation",
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
' *******************************************************************************
2+
' Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
'
4+
' See the NOTICE file(s) distributed with this work for additional
5+
' information regarding copyright ownership.
6+
'
7+
' This program and the accompanying materials are made available under the
8+
' terms of the Apache License Version 2.0 which is available at
9+
' https://www.apache.org/licenses/LICENSE-2.0
10+
'
11+
' SPDX-License-Identifier: Apache-2.0
12+
' *******************************************************************************
13+
14+
@startuml test_de_filegroup_arch_design
15+
16+
package "Test DE Filegroup Arch Design" as test_de_filegroup_arch_design <<SEooC>> {
17+
}
18+
19+
@enduml

bazel/rules/rules_score/test/seooc_test.bzl

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,54 @@ def _seooc_description_test_impl(ctx):
145145
seooc_description_test = analysistest.make(
146146
impl = _seooc_description_test_impl,
147147
)
148+
149+
def _seooc_filegroup_arch_design_test_impl(ctx):
150+
"""Test that dependable_element works when a filegroup is used inside
151+
architectural_design.static.
152+
153+
Verifies:
154+
- index.rst is generated
155+
- The RST file contributed by the filegroup is present in the output files
156+
under the architectural_design/ directory.
157+
"""
158+
env = analysistest.begin(ctx)
159+
target_under_test = analysistest.target_under_test(env)
160+
161+
files = target_under_test[DefaultInfo].files.to_list()
162+
basenames = [f.basename for f in files]
163+
164+
asserts.true(
165+
env,
166+
"index.rst" in basenames,
167+
"Expected index.rst to be generated when architectural_design contains a filegroup",
168+
)
169+
170+
# The filegroup contributes static_architecture.rst; it must appear in outputs
171+
# symlinked under the architectural_design/ subtree.
172+
arch_rst_files = [f for f in files if f.basename == "static_architecture.rst"]
173+
asserts.true(
174+
env,
175+
len(arch_rst_files) > 0,
176+
"Expected static_architecture.rst (from filegroup) to be in output files under architectural_design/",
177+
)
178+
179+
return analysistest.end(env)
180+
181+
seooc_filegroup_arch_design_test = analysistest.make(
182+
impl = _seooc_filegroup_arch_design_test_impl,
183+
)
184+
185+
def _arch_design_invalid_extension_test_impl(ctx):
186+
"""Test that architectural_design fails with a clear error when a filegroup
187+
contains a file with an unsupported extension (e.g. .cc)."""
188+
env = analysistest.begin(ctx)
189+
asserts.expect_failure(
190+
env,
191+
"unsupported extension",
192+
)
193+
return analysistest.end(env)
194+
195+
arch_design_invalid_extension_test = analysistest.make(
196+
impl = _arch_design_invalid_extension_test_impl,
197+
expect_failure = True,
198+
)

0 commit comments

Comments
 (0)