archsight 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/docs/computed_annotations.md +7 -5
- data/docs/licenses.md +1 -2
- data/docs/modeling.md +5 -1
- data/docs/pages.md +63 -6
- data/docs/search.md +17 -0
- data/lib/archsight/annotations/annotation.rb +5 -4
- data/lib/archsight/annotations/computed.rb +5 -1
- data/lib/archsight/annotations/relation_resolver.rb +96 -79
- data/lib/archsight/cli.rb +3 -2
- data/lib/archsight/database.rb +2 -1
- data/lib/archsight/documentation.rb +2 -1
- data/lib/archsight/export/confluence/exporter.rb +11 -2
- data/lib/archsight/export/confluence/storage.rb +99 -8
- data/lib/archsight/export/confluence/tables.rb +78 -0
- data/lib/archsight/helpers/fenced_blocks.rb +61 -0
- data/lib/archsight/helpers/requirements_blocks.rb +90 -0
- data/lib/archsight/helpers/view_blocks.rb +108 -0
- data/lib/archsight/helpers/wiki_links.rb +39 -5
- data/lib/archsight/helpers.rb +3 -0
- data/lib/archsight/import/handlers/go_grapher.rb +4 -1
- data/lib/archsight/import/handlers/go_module_parser.rb +4 -1
- data/lib/archsight/linter.rb +25 -3
- data/lib/archsight/mcp/base.rb +38 -0
- data/lib/archsight/requirements.rb +70 -0
- data/lib/archsight/resources/analysis.rb +2 -1
- data/lib/archsight/resources/application_component.rb +5 -3
- data/lib/archsight/resources/application_interface.rb +4 -2
- data/lib/archsight/resources/application_service.rb +4 -3
- data/lib/archsight/resources/base.rb +27 -12
- data/lib/archsight/resources/business_actor.rb +5 -3
- data/lib/archsight/resources/business_product.rb +4 -3
- data/lib/archsight/resources/business_requirement.rb +4 -3
- data/lib/archsight/resources/compliance_evidence.rb +4 -2
- data/lib/archsight/resources/data_object.rb +2 -1
- data/lib/archsight/resources/import.rb +5 -2
- data/lib/archsight/resources/page.rb +4 -2
- data/lib/archsight/resources/technology_artifact.rb +4 -3
- data/lib/archsight/resources/technology_node.rb +1 -1
- data/lib/archsight/resources/technology_service.rb +4 -0
- data/lib/archsight/resources/technology_system_software.rb +4 -0
- data/lib/archsight/resources/view.rb +2 -1
- data/lib/archsight/version.rb +1 -1
- data/lib/archsight/view_table.rb +102 -0
- data/lib/archsight/web/api/json_helpers.rb +7 -5
- data/lib/archsight/web/api/openapi/spec.yaml +135 -2
- data/lib/archsight/web/api/requirements_helpers.rb +26 -0
- data/lib/archsight/web/api/routes.rb +19 -0
- data/lib/archsight/web/application.rb +6 -1
- data/lib/archsight/web/public/vue/ApiDocsPage-D-cPRZCT.js +1 -0
- data/lib/archsight/web/public/vue/ApiDocsPage-DZ0fa5-h.css +1 -0
- data/lib/archsight/web/public/vue/{DocPage-uaT8CdFm.js → DocPage-DK6vNDbF.js} +1 -1
- data/lib/archsight/web/public/vue/EditorPage-BoJpQaVw.js +35 -0
- data/lib/archsight/web/public/vue/EditorPage-CbG4mc9T.css +1 -0
- data/lib/archsight/web/public/vue/ErrorPage-Ck9izEUS.css +1 -0
- data/lib/archsight/web/public/vue/ErrorPage-PGyjdtEf.js +2 -0
- data/lib/archsight/web/public/vue/GraphView-BLiKR4zP.js +1 -0
- data/lib/archsight/web/public/vue/GraphView-BvWAbUAl.css +1 -0
- data/lib/archsight/web/public/vue/HomePage-C0lR8i2C.js +2 -0
- data/lib/archsight/web/public/vue/InstanceRouter-60Tt3ZNM.css +1 -0
- data/lib/archsight/web/public/vue/InstanceRouter-D3W2jJHV.js +1 -0
- data/lib/archsight/web/public/vue/KindList-BlsaRBNO.js +1 -0
- data/lib/archsight/web/public/vue/PageView-9MgHtrgl.js +1 -0
- data/lib/archsight/web/public/vue/QueryError-3EqjpbyV.css +1 -0
- data/lib/archsight/web/public/vue/QueryError-D1FL1xgA.js +1 -0
- data/lib/archsight/web/public/vue/ResourceList-B0FLaFR3.css +1 -0
- data/lib/archsight/web/public/vue/ResourceList-vkgFyeOY.js +2 -0
- data/lib/archsight/web/public/vue/SearchResults-Cl3O_OEr.js +1 -0
- data/lib/archsight/web/public/vue/SearchResults-DiW5XVYW.css +1 -0
- data/lib/archsight/web/public/vue/WikiPage-C-8SG67a.css +1 -0
- data/lib/archsight/web/public/vue/WikiPage-CeCQBTDS.js +13 -0
- data/lib/archsight/web/public/vue/architecture-7GRP2DOG-BfA1TPxQ.js +1 -0
- data/lib/archsight/web/public/vue/cynefin-OW5HDTMX-BmgdUKVD.js +1 -0
- data/lib/archsight/web/public/vue/eventmodeling-NTZA5JFV-DbXDvAWF.js +1 -0
- data/lib/archsight/web/public/vue/gitGraph-4MIJSDKK-BkVhrKS1.js +1 -0
- data/lib/archsight/web/public/vue/index-D7m61Ahx.js +3 -0
- data/lib/archsight/web/public/vue/index-Dbx3MXWG.css +1 -0
- data/lib/archsight/web/public/vue/info-A6RAGUB7-BIlCVuUY.js +1 -0
- data/lib/archsight/web/public/vue/mermaid-BjEi5URd.js +3334 -0
- data/lib/archsight/web/public/vue/packet-AYTQ26CC-eoQTjY3j.js +1 -0
- data/lib/archsight/web/public/vue/pie-WAS4IAKB-DEOotGhh.js +1 -0
- data/lib/archsight/web/public/vue/radar-RG4KPBEZ-C2yucuUN.js +1 -0
- data/lib/archsight/web/public/vue/railroad-74A4TZTK-CzONK5VY.js +1 -0
- data/lib/archsight/web/public/vue/railroad-abnf-HS5TGJTU-9zRPsDsx.js +1 -0
- data/lib/archsight/web/public/vue/railroad-ebnf-LZEXJU2U-BJ4dkz9l.js +1 -0
- data/lib/archsight/web/public/vue/railroad-peg-WCYAUIDC-DFy_rqAj.js +1 -0
- data/lib/archsight/web/public/vue/treeView-Q6P3EWNA-2cq5CyD2.js +1 -0
- data/lib/archsight/web/public/vue/treemap-WGGIJYW6-DK-e9Ez4.js +1 -0
- data/lib/archsight/web/public/vue/{useGraphviz-C71SdG-N.js → useGraphviz-DweKV7Kg.js} +1 -1
- data/lib/archsight/web/public/vue/wardley-WFR3VGLG-BQwqUqfB.js +1 -0
- data/lib/archsight/web/public/vue.html +3 -3
- data/lib/archsight.rb +2 -0
- metadata +49 -40
- data/lib/archsight/web/public/vue/ApiDocsPage-C0y953v0.css +0 -1
- data/lib/archsight/web/public/vue/ApiDocsPage-C_4tAWis.js +0 -1
- data/lib/archsight/web/public/vue/EditorPage-C557BJC-.js +0 -35
- data/lib/archsight/web/public/vue/EditorPage-df5N-p21.css +0 -1
- data/lib/archsight/web/public/vue/ErrorPage-Vdebmife.js +0 -2
- data/lib/archsight/web/public/vue/ErrorPage-uMDnfY5_.css +0 -1
- data/lib/archsight/web/public/vue/GraphView-BduUql2N.js +0 -1
- data/lib/archsight/web/public/vue/GraphView-Cj2V2stN.css +0 -1
- data/lib/archsight/web/public/vue/HomePage-BHUTg8Ap.js +0 -2
- data/lib/archsight/web/public/vue/InstanceRouter-1lSigA58.js +0 -1
- data/lib/archsight/web/public/vue/InstanceRouter-Di7f3Rya.css +0 -1
- data/lib/archsight/web/public/vue/KindList-BDZs0j6d.js +0 -1
- data/lib/archsight/web/public/vue/PageView-BYzJDwof.js +0 -1
- data/lib/archsight/web/public/vue/ResourceList-CnbhU9wm.js +0 -1
- data/lib/archsight/web/public/vue/ResourceList-xyBwu7fh.css +0 -1
- data/lib/archsight/web/public/vue/SearchResults-CNhf6VOx.js +0 -1
- data/lib/archsight/web/public/vue/SearchResults-DOHzqAy3.css +0 -1
- data/lib/archsight/web/public/vue/WikiPage-DbmWkM7W.js +0 -13
- data/lib/archsight/web/public/vue/WikiPage-GV67QmNJ.css +0 -1
- data/lib/archsight/web/public/vue/architecture-TIHT7OUA-Bf-MWFmn.js +0 -1
- data/lib/archsight/web/public/vue/cynefin-VYW2F7L2-CkKt8qqs.js +0 -1
- data/lib/archsight/web/public/vue/eventmodeling-45OFAUF4-NwSTYPHj.js +0 -1
- data/lib/archsight/web/public/vue/gitGraph-TEB2WS4Q-DLRegrRG.js +0 -1
- data/lib/archsight/web/public/vue/index-CyVWObLU.js +0 -3
- data/lib/archsight/web/public/vue/index-DtKeHT3S.css +0 -1
- data/lib/archsight/web/public/vue/info-DKCQHKI2-EV39NzoN.js +0 -1
- data/lib/archsight/web/public/vue/mermaid-BMkGfnhm.js +0 -3279
- data/lib/archsight/web/public/vue/packet-7NZHBO7P-USljV3MZ.js +0 -1
- data/lib/archsight/web/public/vue/pie-RZYD4A2V-DChciBW2.js +0 -1
- data/lib/archsight/web/public/vue/radar-I7S5WNFK-CgGJdW1t.js +0 -1
- data/lib/archsight/web/public/vue/railroad-3IZDKUUU-Dy43vF5c.js +0 -1
- data/lib/archsight/web/public/vue/railroad-abnf-AHOZXSZD-BhsTH-sE.js +0 -1
- data/lib/archsight/web/public/vue/railroad-ebnf-EBAXGLYW-BBTd_u0u.js +0 -1
- data/lib/archsight/web/public/vue/railroad-peg-LSFZ7HO6-BiNTEzf0.js +0 -1
- data/lib/archsight/web/public/vue/treeView-QDETBFTQ-BfnCcf-q.js +0 -1
- data/lib/archsight/web/public/vue/treemap-6X3UGDF4-BsAORhvk.js +0 -1
- data/lib/archsight/web/public/vue/wardley-OPB4EBWU-DQvnEhRj.js +0 -1
data/lib/archsight/linter.rb
CHANGED
|
@@ -107,6 +107,8 @@ module Archsight
|
|
|
107
107
|
@errors << "#{instance.path_ref}: Markdown syntax error in annotation '#{key}': #{e.message}"
|
|
108
108
|
end
|
|
109
109
|
validate_diagram_blocks(instance, key, value)
|
|
110
|
+
validate_view_blocks(instance, key, value)
|
|
111
|
+
validate_requirements_blocks(instance, key, value)
|
|
110
112
|
validate_asset_images(instance, key, value)
|
|
111
113
|
validate_embeds(instance, key, value)
|
|
112
114
|
end
|
|
@@ -161,6 +163,25 @@ module Archsight
|
|
|
161
163
|
end
|
|
162
164
|
end
|
|
163
165
|
|
|
166
|
+
# Every ```view block must be a valid View, or the page shows an error box instead of the view
|
|
167
|
+
def validate_view_blocks(instance, key, value)
|
|
168
|
+
Helpers::ViewBlocks.sources(value).each_with_index do |source, index|
|
|
169
|
+
spec = Helpers::ViewBlocks.parse(source)
|
|
170
|
+
check_view_components(instance, spec[:fields])
|
|
171
|
+
rescue Helpers::ViewBlocks::Error => e
|
|
172
|
+
@errors << "#{instance.path_ref}: View error in annotation '#{key}' (view block #{index + 1}): #{e.message}"
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Every ```requirements block must be a valid filter, or the page shows an error box instead of the table
|
|
177
|
+
def validate_requirements_blocks(instance, key, value)
|
|
178
|
+
Helpers::RequirementsBlocks.sources(value).each_with_index do |source, index|
|
|
179
|
+
Helpers::RequirementsBlocks.parse(source)
|
|
180
|
+
rescue Helpers::RequirementsBlocks::Error => e
|
|
181
|
+
@errors << "#{instance.path_ref}: Requirements error in annotation '#{key}' (requirements block #{index + 1}): #{e.message}"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
164
185
|
# Renders with the same resolver the web UI uses, so a `resource` reference that would show as a broken link there is reported here
|
|
165
186
|
def render_diagram_source(instance, where, source)
|
|
166
187
|
unresolved = []
|
|
@@ -173,10 +194,11 @@ module Archsight
|
|
|
173
194
|
end
|
|
174
195
|
|
|
175
196
|
def validate_view_fields(instance)
|
|
176
|
-
|
|
177
|
-
|
|
197
|
+
check_view_components(instance, instance.annotations["view/fields"].to_s.split(",").map(&:strip))
|
|
198
|
+
end
|
|
178
199
|
|
|
179
|
-
|
|
200
|
+
def check_view_components(instance, fields)
|
|
201
|
+
fields.each do |field|
|
|
180
202
|
next unless field.start_with?("@")
|
|
181
203
|
|
|
182
204
|
component_name = field[1..]
|
data/lib/archsight/mcp/base.rb
CHANGED
|
@@ -38,6 +38,20 @@ module Archsight::MCP
|
|
|
38
38
|
result
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
# The summary attributes of a resource's kind (annotations marked `summary: true`) that have a value,
|
|
42
|
+
# as [{key:, title:, value:, format:, type:}]. Computed annotations are included; they are precomputed
|
|
43
|
+
# at load and absent when empty. Lists (filter: :list) come back as arrays, Integer/Float typed values
|
|
44
|
+
# as numbers, `type` is the short type name ("Integer", "Time", "Person", ...) or nil.
|
|
45
|
+
def highlights(resource)
|
|
46
|
+
resource.class.summary_annotations.filter_map do |annotation|
|
|
47
|
+
value = highlight_value(annotation, resource)
|
|
48
|
+
next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
49
|
+
|
|
50
|
+
{ key: annotation.key, title: annotation.title, value: value, format: annotation.format,
|
|
51
|
+
type: short_type_name(annotation.type) }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
41
55
|
def extract_description(resource)
|
|
42
56
|
description = resource.annotations["architecture/description"]
|
|
43
57
|
return "No description" if description.nil?
|
|
@@ -45,6 +59,30 @@ module Archsight::MCP
|
|
|
45
59
|
description.split("\n").first
|
|
46
60
|
end
|
|
47
61
|
|
|
62
|
+
def short_type_name(type)
|
|
63
|
+
type&.name.to_s.split("::").last
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The hit's kind name ("TechnologyArtifact") and the number of hits per kind
|
|
67
|
+
def kind_of(resource)
|
|
68
|
+
resource.class.to_s.split("::").last
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def count_by_kind(results)
|
|
72
|
+
results.group_by { |r| kind_of(r) }.transform_values(&:length)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def highlight_value(annotation, resource)
|
|
76
|
+
value = annotation.value_for(resource)
|
|
77
|
+
return value unless value.is_a?(String)
|
|
78
|
+
|
|
79
|
+
case annotation.type&.name
|
|
80
|
+
when "Integer" then value.match?(/\A-?\d+\z/) ? value.to_i : value
|
|
81
|
+
when "Float" then value.match?(/\A-?\d+(\.\d+)?\z/) ? value.to_f : value
|
|
82
|
+
else value
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
48
86
|
def extract_relations(instance)
|
|
49
87
|
relations = {}
|
|
50
88
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Archsight
|
|
4
|
+
# The business requirements of a selection of resources, as the "Business Requirements" table of an instance page
|
|
5
|
+
# shows them, merged over all resources of the selection: one entry per BusinessRequirement, with the status the
|
|
6
|
+
# resources give it (`realizes` = implemented, `partiallyRealizes` = partial, `plans` = planned).
|
|
7
|
+
#
|
|
8
|
+
# Requirements.collect(db, of: 'ApplicationService: name =~ "Backup"', priority: ["must"])
|
|
9
|
+
# # => [{ name: "Requirement:X", status: "partial", priority: "must", story: "...",
|
|
10
|
+
# # by: [{ kind: "ApplicationService", name: "Backup", status: "partial" }] }]
|
|
11
|
+
module Requirements
|
|
12
|
+
# Relation verb -> status, best first
|
|
13
|
+
STATUSES = { "realizes" => "implemented", "partiallyRealizes" => "partial", "plans" => "planned" }.freeze
|
|
14
|
+
PRIORITIES = %w[must should may].freeze
|
|
15
|
+
RELATION = :businessRequirements
|
|
16
|
+
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
# @param of [String] query selecting the resources whose requirements are listed
|
|
20
|
+
# @param priority [Array<String>] only these priorities (empty: all)
|
|
21
|
+
# @param status [Array<String>] only requirements with one of these statuses (empty: all)
|
|
22
|
+
# @return [Array<Hash>] sorted by priority (must, should, may, none), then name
|
|
23
|
+
# @raise [Archsight::Query::QueryError] if `of` is not a valid query
|
|
24
|
+
def collect(database, of:, priority: [], status: [])
|
|
25
|
+
found = {}
|
|
26
|
+
Archsight::Query.parse(of).filter(database).each do |resource|
|
|
27
|
+
STATUSES.each do |verb, resource_status|
|
|
28
|
+
resource.relations(verb, RELATION).each do |requirement|
|
|
29
|
+
entry = (found[requirement.name] ||= { requirement: requirement, by: [] })
|
|
30
|
+
entry[:by] << { kind: resource.class.name.split("::").last, name: resource.name, status: resource_status }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
entries = found.values.map { |entry| entry(entry[:requirement], entry[:by]) }
|
|
36
|
+
entries = entries.select { |e| priority.include?(e[:priority]) } unless priority.empty?
|
|
37
|
+
entries = entries.select { |e| status.include?(e[:status]) } unless status.empty?
|
|
38
|
+
entries.sort_by { |e| [PRIORITIES.index(e[:priority]) || PRIORITIES.size, e[:name]] }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# The requirements of a ```requirements block as a plain table (see ViewTable), for places that cannot run the frontend.
|
|
42
|
+
# "Realized by" is only there when more than one resource contributes.
|
|
43
|
+
# @param spec [Hash] the parsed block: `{ title:, of:, priority:, status: }` (Helpers::RequirementsBlocks.parse)
|
|
44
|
+
# @raise [Archsight::Query::QueryError]
|
|
45
|
+
def table(database, spec)
|
|
46
|
+
entries = collect(database, of: spec[:of], priority: spec[:priority], status: spec[:status])
|
|
47
|
+
with_by = entries.flat_map { |e| e[:by].map { |b| [b[:kind], b[:name]] } }.uniq.length > 1
|
|
48
|
+
cell = ViewTable::Cell
|
|
49
|
+
rows = entries.first(ViewTable::LIMIT).map do |e|
|
|
50
|
+
row = [cell.new(text: e[:status], as: :status), cell.new(text: e[:name]), cell.new(text: e[:priority].to_s, as: :priority),
|
|
51
|
+
cell.new(text: e[:story].to_s, as: :markdown)]
|
|
52
|
+
row << cell.new(text: e[:by].map { |b| b[:name] }.join("\n")) if with_by
|
|
53
|
+
row
|
|
54
|
+
end
|
|
55
|
+
ViewTable::Table.new(title: spec[:title].to_s.empty? ? "Business Requirements" : spec[:title],
|
|
56
|
+
columns: ["Status", "Name", "Priority", "Story", ("Realized by" if with_by)].compact, rows: rows, total: entries.length)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def entry(requirement, by)
|
|
60
|
+
by = by.sort_by { |b| [STATUSES.values.index(b[:status]), b[:kind], b[:name]] }
|
|
61
|
+
{
|
|
62
|
+
name: requirement.name,
|
|
63
|
+
status: by.first[:status],
|
|
64
|
+
priority: requirement.annotations["requirement/priority"],
|
|
65
|
+
story: requirement.annotations["requirement/story"],
|
|
66
|
+
by: by
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -45,7 +45,8 @@ class Archsight::Resources::Analysis < Archsight::Resources::Base
|
|
|
45
45
|
annotation "analysis/handler",
|
|
46
46
|
description: "Script handler type (only 'ruby' currently supported)",
|
|
47
47
|
title: "Handler",
|
|
48
|
-
enum: %w[ruby]
|
|
48
|
+
enum: %w[ruby],
|
|
49
|
+
summary: true
|
|
49
50
|
|
|
50
51
|
# Script content
|
|
51
52
|
annotation "analysis/script",
|
|
@@ -141,13 +141,15 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
|
|
|
141
141
|
annotation "deployment/cluster",
|
|
142
142
|
description: "Target cluster name",
|
|
143
143
|
title: "Cluster",
|
|
144
|
-
filter: :word
|
|
144
|
+
filter: :word,
|
|
145
|
+
summary: true
|
|
145
146
|
|
|
146
147
|
# Computed Annotations
|
|
147
148
|
computed_annotation "repository/artifacts/total",
|
|
148
149
|
title: "Total Git Repositories",
|
|
149
150
|
description: "Number of related git repositories",
|
|
150
|
-
type: Integer
|
|
151
|
+
type: Integer,
|
|
152
|
+
summary: true do
|
|
151
153
|
count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo"'))
|
|
152
154
|
end
|
|
153
155
|
|
|
@@ -190,7 +192,7 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
|
|
|
190
192
|
|
|
191
193
|
computed_annotation "scc/language",
|
|
192
194
|
title: "Primary Language",
|
|
193
|
-
|
|
195
|
+
summary: true,
|
|
194
196
|
description: "Programming language with most lines of code across related artifacts",
|
|
195
197
|
filter: :word,
|
|
196
198
|
sidebar: true do
|
|
@@ -34,11 +34,13 @@ class Archsight::Resources::ApplicationInterface < Archsight::Resources::Base
|
|
|
34
34
|
annotation "api/responsiveness",
|
|
35
35
|
description: "API 99th percentile responsiveness target",
|
|
36
36
|
title: "API Responsiveness (99p)",
|
|
37
|
-
enum: %w[10ms 100ms 1000ms 2s 5s 10s unresponsive]
|
|
37
|
+
enum: %w[10ms 100ms 1000ms 2s 5s 10s unresponsive],
|
|
38
|
+
summary: true
|
|
38
39
|
annotation "api/authenticationMethod",
|
|
39
40
|
description: "API authentication method",
|
|
40
41
|
title: "API Authentication Method",
|
|
41
|
-
enum: ["none", "hard coded", "token", "oidc"]
|
|
42
|
+
enum: ["none", "hard coded", "token", "oidc"],
|
|
43
|
+
summary: true
|
|
42
44
|
annotation "api/authorization",
|
|
43
45
|
description: "API authorization mechanism",
|
|
44
46
|
title: "API Authorization",
|
|
@@ -34,13 +34,14 @@ class Archsight::Resources::ApplicationService < Archsight::Resources::Base
|
|
|
34
34
|
description: "Service plane classification (control manages resources, data handles traffic)",
|
|
35
35
|
title: "Service Plane",
|
|
36
36
|
enum: %w[control data],
|
|
37
|
-
|
|
37
|
+
summary: true
|
|
38
38
|
|
|
39
39
|
# Computed Annotations
|
|
40
40
|
computed_annotation "repository/artifacts/total",
|
|
41
41
|
title: "Total Git Repositories",
|
|
42
42
|
description: "Number of related git repositories",
|
|
43
|
-
type: Integer
|
|
43
|
+
type: Integer,
|
|
44
|
+
summary: true do
|
|
44
45
|
count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo"'))
|
|
45
46
|
end
|
|
46
47
|
|
|
@@ -83,7 +84,7 @@ class Archsight::Resources::ApplicationService < Archsight::Resources::Base
|
|
|
83
84
|
|
|
84
85
|
computed_annotation "scc/languages",
|
|
85
86
|
title: "Primary Languages",
|
|
86
|
-
|
|
87
|
+
summary: true,
|
|
87
88
|
description: "Top 4 programming languages by lines of code across related artifacts",
|
|
88
89
|
filter: :list,
|
|
89
90
|
sidebar: true do
|
|
@@ -23,13 +23,29 @@ module Archsight
|
|
|
23
23
|
@relations || []
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
# A kind may mark at most this many annotations as summary (see Base.annotation)
|
|
27
|
+
MAX_SUMMARY_ANNOTATIONS = 3
|
|
28
|
+
|
|
26
29
|
# Define an annotation using the Annotation class
|
|
30
|
+
# `summary: true` marks it as a summary attribute: it is returned with every search hit of this kind.
|
|
27
31
|
def self.annotation(key, description: nil, filter: nil, title: nil, format: nil, enum: nil, sidebar: true,
|
|
28
|
-
type: nil,
|
|
29
|
-
@annotations ||= [] #: Array[Archsight::Annotations::Annotation]
|
|
32
|
+
type: nil, summary: false, editor: true, validator: nil)
|
|
30
33
|
options = { description: description, filter: filter, title: title, format: format, enum: enum,
|
|
31
|
-
sidebar: sidebar, type: type,
|
|
32
|
-
|
|
34
|
+
sidebar: sidebar, type: type, summary: summary, editor: editor, validator: validator }
|
|
35
|
+
register_annotation(Archsight::Annotations::Annotation.new(key, options))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Append an annotation definition, enforcing the limit of summary annotations per kind.
|
|
39
|
+
# Annotations of included modules (include_annotations) come through here as well.
|
|
40
|
+
def self.register_annotation(annotation)
|
|
41
|
+
@annotations ||= [] #: Array[Archsight::Annotations::Annotation]
|
|
42
|
+
if annotation.summary? && @annotations.count(&:summary?) >= MAX_SUMMARY_ANNOTATIONS
|
|
43
|
+
raise ArgumentError,
|
|
44
|
+
"#{name}: at most #{MAX_SUMMARY_ANNOTATIONS} annotations can be summary attributes, " \
|
|
45
|
+
"cannot add #{annotation.key}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@annotations << annotation
|
|
33
49
|
end
|
|
34
50
|
|
|
35
51
|
# Get all annotation definitions
|
|
@@ -48,19 +64,18 @@ module Archsight
|
|
|
48
64
|
# @param enum [Array, nil] Allowed values
|
|
49
65
|
# @param sidebar [Boolean] Show in sidebar (default false for computed)
|
|
50
66
|
# @param type [Class, nil] Type for value coercion (Integer, Float, String)
|
|
51
|
-
# @param
|
|
67
|
+
# @param summary [Boolean] Return the value with every search hit of this kind (default false, max 3 per kind)
|
|
52
68
|
# @yield Block that computes the annotation value, evaluated in Evaluator context
|
|
53
69
|
def self.computed_annotation(key, description: nil, filter: nil, title: nil, format: nil, enum: nil,
|
|
54
|
-
sidebar: false, type: nil,
|
|
70
|
+
sidebar: false, type: nil, summary: false, editor: true, &)
|
|
55
71
|
require_relative "../annotations/computed"
|
|
56
72
|
@computed_annotations ||= [] #: Array[Archsight::Annotations::Computed]
|
|
57
73
|
@computed_annotations << Archsight::Annotations::Computed.new(key, description: description, type: type, &)
|
|
58
74
|
|
|
59
75
|
# Also register as a regular annotation so it passes validation and is recognized
|
|
60
|
-
@annotations ||= [] #: Array[Archsight::Annotations::Annotation]
|
|
61
76
|
options = { description: description, filter: filter, title: title, format: format, enum: enum,
|
|
62
|
-
sidebar: sidebar, type: type,
|
|
63
|
-
|
|
77
|
+
sidebar: sidebar, type: type, summary: summary, editor: editor }
|
|
78
|
+
register_annotation(Archsight::Annotations::Annotation.new(key, options))
|
|
64
79
|
end
|
|
65
80
|
|
|
66
81
|
# Get all computed annotation definitions
|
|
@@ -83,9 +98,9 @@ module Archsight
|
|
|
83
98
|
annotations.select(&:filterable?).reject(&:pattern?)
|
|
84
99
|
end
|
|
85
100
|
|
|
86
|
-
# Get annotations marked
|
|
87
|
-
def self.
|
|
88
|
-
annotations.select(&:
|
|
101
|
+
# Get the annotations marked as summary attributes (returned with search hits)
|
|
102
|
+
def self.summary_annotations
|
|
103
|
+
annotations.select(&:summary?).reject(&:pattern?)
|
|
89
104
|
end
|
|
90
105
|
|
|
91
106
|
def self.annotation_title(key)
|
|
@@ -36,7 +36,8 @@ class Archsight::Resources::BusinessActor < Archsight::Resources::Base
|
|
|
36
36
|
sidebar: false,
|
|
37
37
|
filter: :word,
|
|
38
38
|
format: :tag_word,
|
|
39
|
-
type: Archsight::Annotations::EmailRecipient
|
|
39
|
+
type: Archsight::Annotations::EmailRecipient,
|
|
40
|
+
summary: true
|
|
40
41
|
|
|
41
42
|
annotation "team/members",
|
|
42
43
|
description: 'Team members (format: "Name <email>" or "email")',
|
|
@@ -108,7 +109,7 @@ class Archsight::Resources::BusinessActor < Archsight::Resources::Base
|
|
|
108
109
|
computed_annotation "team/size",
|
|
109
110
|
title: "Team Size",
|
|
110
111
|
description: "Number of team members (including sub-teams)",
|
|
111
|
-
|
|
112
|
+
summary: true,
|
|
112
113
|
type: Integer do
|
|
113
114
|
# Count members from this team
|
|
114
115
|
members = @instance.annotations["team/members"]
|
|
@@ -147,7 +148,8 @@ class Archsight::Resources::BusinessActor < Archsight::Resources::Base
|
|
|
147
148
|
computed_annotation "repository/artifacts/total",
|
|
148
149
|
title: "Maintained Repositories",
|
|
149
150
|
description: "Number of git repositories maintained by this team",
|
|
150
|
-
type: Integer
|
|
151
|
+
type: Integer,
|
|
152
|
+
summary: true do
|
|
151
153
|
count(incoming_transitive('TechnologyArtifact: artifact/type == "repo"'))
|
|
152
154
|
end
|
|
153
155
|
|
|
@@ -33,7 +33,8 @@ class Archsight::Resources::BusinessProduct < Archsight::Resources::Base
|
|
|
33
33
|
computed_annotation "repository/artifacts/total",
|
|
34
34
|
title: "Total Git Repositories",
|
|
35
35
|
description: "Number of related git repositories",
|
|
36
|
-
type: Integer
|
|
36
|
+
type: Integer,
|
|
37
|
+
summary: true do
|
|
37
38
|
count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo"'))
|
|
38
39
|
end
|
|
39
40
|
|
|
@@ -110,7 +111,7 @@ class Archsight::Resources::BusinessProduct < Archsight::Resources::Base
|
|
|
110
111
|
computed_annotation "activity/createdAt",
|
|
111
112
|
title: "Created",
|
|
112
113
|
description: "Earliest repository creation date across all related application services",
|
|
113
|
-
|
|
114
|
+
summary: true,
|
|
114
115
|
type: Time do
|
|
115
116
|
services = outgoing_transitive(:ApplicationService)
|
|
116
117
|
next nil if services.empty?
|
|
@@ -170,7 +171,7 @@ class Archsight::Resources::BusinessProduct < Archsight::Resources::Base
|
|
|
170
171
|
computed_annotation "activity/contributors/6m",
|
|
171
172
|
title: "Contributors (6 months)",
|
|
172
173
|
description: "Sum of unique contributors in the last 6 months across related services",
|
|
173
|
-
|
|
174
|
+
summary: true,
|
|
174
175
|
type: Integer do
|
|
175
176
|
services = outgoing_transitive(:ApplicationService)
|
|
176
177
|
next nil if services.empty?
|
|
@@ -32,20 +32,21 @@ class Archsight::Resources::BusinessRequirement < Archsight::Resources::Base
|
|
|
32
32
|
|
|
33
33
|
annotation "requirement/type",
|
|
34
34
|
description: "Type of requirement (business or legal)",
|
|
35
|
-
enum: %w[business legal compliance functional non-functional]
|
|
35
|
+
enum: %w[business legal compliance functional non-functional],
|
|
36
|
+
summary: true
|
|
36
37
|
|
|
37
38
|
annotation "requirement/reference",
|
|
38
39
|
description: "Regulatory or standard reference (comma-separated for multiple)",
|
|
39
40
|
filter: :list,
|
|
40
41
|
enum: %w[c5-2020 itgs-2023 gdpr-2018 nis1 nis2 iso27001 sox pci-dss hipaa eu-data-act-2025 ens
|
|
41
42
|
iso27001-2022],
|
|
42
|
-
|
|
43
|
+
summary: true
|
|
43
44
|
|
|
44
45
|
annotation "requirement/priority",
|
|
45
46
|
description: "Implementation priority (must, should, may)",
|
|
46
47
|
filter: :word,
|
|
47
48
|
enum: %w[must should may],
|
|
48
|
-
|
|
49
|
+
summary: true
|
|
49
50
|
|
|
50
51
|
annotation "requirement/story",
|
|
51
52
|
description: "One-line business value statement explaining what the requirement enables",
|
|
@@ -32,11 +32,13 @@ class Archsight::Resources::ComplianceEvidence < Archsight::Resources::Base
|
|
|
32
32
|
|
|
33
33
|
annotation "evidence/type",
|
|
34
34
|
description: "Type of evidence",
|
|
35
|
-
enum: %w[documentation process configuration audit-log technical-control]
|
|
35
|
+
enum: %w[documentation process configuration audit-log technical-control],
|
|
36
|
+
summary: true
|
|
36
37
|
|
|
37
38
|
annotation "evidence/status",
|
|
38
39
|
description: "Current status of evidence",
|
|
39
|
-
enum: %w[implemented partial not-implemented]
|
|
40
|
+
enum: %w[implemented partial not-implemented],
|
|
41
|
+
summary: true
|
|
40
42
|
|
|
41
43
|
relation :satisfies, :businessRequirements, :BusinessRequirement
|
|
42
44
|
end
|
|
@@ -38,7 +38,8 @@ class Archsight::Resources::DataObject < Archsight::Resources::Base
|
|
|
38
38
|
annotation "data/visibility",
|
|
39
39
|
description: "API visibility level",
|
|
40
40
|
title: "Visibility",
|
|
41
|
-
enum: %w[public private internal]
|
|
41
|
+
enum: %w[public private internal],
|
|
42
|
+
summary: true
|
|
42
43
|
|
|
43
44
|
annotation "generated/variants",
|
|
44
45
|
description: "OpenAPI schema variants compacted into this DataObject",
|
|
@@ -38,7 +38,9 @@ class Archsight::Resources::Import < Archsight::Resources::Base
|
|
|
38
38
|
# Handler selection
|
|
39
39
|
annotation "import/handler",
|
|
40
40
|
description: "Handler class name to execute this import",
|
|
41
|
-
title: "Handler",
|
|
41
|
+
title: "Handler",
|
|
42
|
+
summary: true,
|
|
43
|
+
enum: %w[
|
|
42
44
|
gitlab github repository
|
|
43
45
|
rest-api rest-api-index
|
|
44
46
|
jira-discover jira-metrics
|
|
@@ -57,7 +59,8 @@ class Archsight::Resources::Import < Archsight::Resources::Base
|
|
|
57
59
|
annotation "import/enabled",
|
|
58
60
|
description: "Whether this import is enabled",
|
|
59
61
|
title: "Enabled",
|
|
60
|
-
enum: %w[true false]
|
|
62
|
+
enum: %w[true false],
|
|
63
|
+
summary: true
|
|
61
64
|
|
|
62
65
|
annotation "import/priority",
|
|
63
66
|
description: "Execution priority (lower runs first among ready imports)",
|
|
@@ -38,11 +38,13 @@ class Archsight::Resources::Page < Archsight::Resources::Base
|
|
|
38
38
|
description: "Owner responsible for keeping the page up to date (Name <email@domain.com>, or just a name)",
|
|
39
39
|
title: "Owner",
|
|
40
40
|
type: Archsight::Annotations::Person,
|
|
41
|
-
sidebar: false
|
|
41
|
+
sidebar: false,
|
|
42
|
+
summary: true
|
|
42
43
|
annotation "page/status",
|
|
43
44
|
description: "Lifecycle status (e.g. rfc, wip, approved)",
|
|
44
45
|
filter: :word,
|
|
45
|
-
title: "Status"
|
|
46
|
+
title: "Status",
|
|
47
|
+
summary: true
|
|
46
48
|
annotation "page/tags",
|
|
47
49
|
description: "Comma-separated tags",
|
|
48
50
|
filter: :list,
|
|
@@ -74,7 +74,7 @@ class Archsight::Resources::TechnologyArtifact < Archsight::Resources::Base
|
|
|
74
74
|
description: "Repository activity status",
|
|
75
75
|
title: "Activity Status",
|
|
76
76
|
enum: %w[active abandoned bot-only archived inaccessible empty no-code],
|
|
77
|
-
|
|
77
|
+
summary: true
|
|
78
78
|
annotation "activity/reason",
|
|
79
79
|
description: "Reason for activity status (for non-standard statuses)",
|
|
80
80
|
title: "Status Reason",
|
|
@@ -83,7 +83,7 @@ class Archsight::Resources::TechnologyArtifact < Archsight::Resources::Base
|
|
|
83
83
|
description: "Bus factor assessment",
|
|
84
84
|
title: "Bus Factor",
|
|
85
85
|
enum: %w[high medium low unknown],
|
|
86
|
-
|
|
86
|
+
summary: true
|
|
87
87
|
annotation "activity/createdAt",
|
|
88
88
|
description: "Date of first commit (repository creation)",
|
|
89
89
|
title: "Created",
|
|
@@ -130,7 +130,8 @@ class Archsight::Resources::TechnologyArtifact < Archsight::Resources::Base
|
|
|
130
130
|
annotation "repository/visibility",
|
|
131
131
|
description: "Repository visibility classification",
|
|
132
132
|
title: "Visibility",
|
|
133
|
-
enum: %w[private internal open-source public]
|
|
133
|
+
enum: %w[private internal open-source public],
|
|
134
|
+
summary: true
|
|
134
135
|
annotation "repository/recentTags",
|
|
135
136
|
description: "Recent git tags (releases)",
|
|
136
137
|
title: "Recent Tags",
|
|
@@ -34,7 +34,7 @@ class Archsight::Resources::TechnologyNode < Archsight::Resources::Base
|
|
|
34
34
|
description: "Type of infrastructure node",
|
|
35
35
|
title: "Infrastructure Type",
|
|
36
36
|
enum: %w[vm bare-metal kubernetes-node network-appliance storage-array],
|
|
37
|
-
|
|
37
|
+
summary: true
|
|
38
38
|
|
|
39
39
|
relation :realizes, :businessConstraints, :BusinessConstraint
|
|
40
40
|
relation :servedBy, :technologyServices, :TechnologyService
|
|
@@ -37,4 +37,8 @@ class Archsight::Resources::TechnologyService < Archsight::Resources::Base
|
|
|
37
37
|
|
|
38
38
|
relation :suppliedBy, :technologyComponents, :TechnologySystemSoftware
|
|
39
39
|
relation :servedBy, :businessActors, :BusinessActor
|
|
40
|
+
relation :realizes, :businessRequirements, :BusinessRequirement
|
|
41
|
+
relation :partiallyRealizes, :businessRequirements, :BusinessRequirement
|
|
42
|
+
relation :plans, :businessRequirements, :BusinessRequirement
|
|
43
|
+
relation :evidencedBy, :complianceEvidences, :ComplianceEvidence
|
|
40
44
|
end
|
|
@@ -34,4 +34,8 @@ class Archsight::Resources::TechnologySystemSoftware < Archsight::Resources::Bas
|
|
|
34
34
|
relation :realizedThrough, :technologyArtifacts, :TechnologyArtifact
|
|
35
35
|
relation :exposes, :applicationInterfaces, :ApplicationInterface
|
|
36
36
|
relation :dependsOn, :applicationInterfaces, :ApplicationInterface
|
|
37
|
+
relation :realizes, :businessRequirements, :BusinessRequirement
|
|
38
|
+
relation :partiallyRealizes, :businessRequirements, :BusinessRequirement
|
|
39
|
+
relation :plans, :businessRequirements, :BusinessRequirement
|
|
40
|
+
relation :evidencedBy, :complianceEvidences, :ComplianceEvidence
|
|
37
41
|
end
|
|
@@ -42,7 +42,8 @@ class Archsight::Resources::View < Archsight::Resources::Base
|
|
|
42
42
|
description: "Display type for results",
|
|
43
43
|
title: "Display Type",
|
|
44
44
|
enum: %w[list:name list:name+kind],
|
|
45
|
-
sidebar: false
|
|
45
|
+
sidebar: false,
|
|
46
|
+
summary: true
|
|
46
47
|
|
|
47
48
|
annotation "view/sort",
|
|
48
49
|
description: 'Comma-separated list of fields to sort by. Prefix with - for descending (e.g., "-scc/language/Go/loc,name"). Special fields: name, kind',
|
data/lib/archsight/version.rb
CHANGED