archsight 0.2.5 → 0.2.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0c195f805808234600e39cd6a3f80cf2ee105c9aaec92d29aca78795f634c4e
4
- data.tar.gz: c0ecdcd65b22cd03567fc3e28a03b5b7eb0607114ba5e5950e05b744b3dd7a5f
3
+ metadata.gz: a648a562357c7e62c60c815f87e7ef83dbae73b545c0ee3f1ef21e983e705728
4
+ data.tar.gz: b2770c7f3d769a8fc45c9a3d8dfe947454a2054bccf0075206865b1a4b8dbbf5
5
5
  SHA512:
6
- metadata.gz: 5380e24d80507b0bb223f9351e5e0efc18cd3d9119dd0c34ee810404992da87714e7d444fd7a3d70f8dfa4dada77edb989018d4b21914100fb1782d5df4f8177
7
- data.tar.gz: b88868e7b3656eb45920b92a7eed4ea7ae453bacff1b41a659b95bea52210d7c789f05184db51a3de9590b42f4a854b33a64f22f42fce4fc40519a8a18b89e99
6
+ metadata.gz: 1cb930e83f808190b15c487226b84db7152981497f0a81746ee96bebd3e10c3b717f2be3765f95e0c42f07725d51cdfdb7bfcfda972b0dd0b76d7108dd99d4d9
7
+ data.tar.gz: a7384b1d52afbe08c5108d0fba87d7c5407eb70c52a7bf6db782ff66036b224637405c49bf105b6afb46f815e5daa3c6cb5a191f69d14834638998a757fa185b
data/lib/archsight/cli.rb CHANGED
@@ -176,8 +176,14 @@ module Archsight
176
176
  require_import_handlers
177
177
 
178
178
  # Create database that loads from resources directory
179
- # Only load Import resources to avoid validation errors on incomplete resources
180
- db = Archsight::Database.new(resources_dir, verbose: options[:verbose], only_kinds: %w[Import BusinessActor], verify: false)
179
+ # Only load the kinds that import handlers inspect at runtime (ApplicationComponent
180
+ # and ApplicationInterface for GoGrapher/GoDepResolver cross-referencing, BusinessActor
181
+ # for repository handler owner lookup). Validation is disabled because resources may be
182
+ # in an incomplete state during an in-progress import run.
183
+ db = Archsight::Database.new(resources_dir,
184
+ verbose: options[:verbose],
185
+ only_kinds: %w[Import BusinessActor ApplicationComponent ApplicationInterface],
186
+ verify: false)
181
187
 
182
188
  if options[:dry_run]
183
189
  puts "Execution Plan:"
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require_relative "../handler"
5
+ require_relative "go_module_parser"
6
+ require_relative "../registry"
7
+
8
+ # GoDepResolver handler - second-pass resolver that patches dependsOn relations
9
+ # onto ApplicationComponents generated by GoGrapher.
10
+ #
11
+ # Runs after all GoGraphers complete (iteration 2 of the executor loop) so the
12
+ # database contains the full set of freshly-generated ApplicationComponents.
13
+ # Output goes to a single shared generated/relationships.yaml file (all repos
14
+ # combined), loaded after modules.yaml alphabetically so its version of each
15
+ # component — with dependsOn — takes precedence.
16
+ #
17
+ # One Import:GoDepResolver:* resource is emitted by each GoGrapher run; this
18
+ # handler is registered as a child of GoGrapher via the generates relation so
19
+ # the executor knows to wait until GoGrapher has completed.
20
+ #
21
+ # Configuration:
22
+ # import/config/path - Path to the Go repository root (same as GoGrapher)
23
+ class Archsight::Import::Handlers::GoDepResolver < Archsight::Import::Handler
24
+ include Archsight::Import::Handlers::GoModuleParser
25
+
26
+ def execute
27
+ @path = config("path")
28
+ raise "Missing required config: path" unless @path
29
+ raise "Directory not found: #{@path}" unless File.directory?(@path)
30
+
31
+ import_resource.annotations["import/outputPath"] ||= "generated/relationships.yaml"
32
+
33
+ modules = discover_modules(@path)
34
+ return write_yaml(YAML.dump(self_marker)) if modules.empty?
35
+
36
+ existing_components = database&.instances_by_kind("ApplicationComponent") || {}
37
+ output = +""
38
+
39
+ modules.each do |rel_dir, mod_name|
40
+ mod_dir = rel_dir == "." ? @path : File.join(@path, rel_dir)
41
+ dep_names = compute_deps(mod_dir, mod_name, existing_components)
42
+ next if dep_names.empty?
43
+
44
+ comp_name = component_name(mod_name)
45
+ existing = existing_components[comp_name]
46
+ next unless existing
47
+
48
+ # Rebuild the full ApplicationComponent merging dependsOn into the existing
49
+ # spec (which carries realizedThrough, exposes, etc. from GoGrapher).
50
+ spec = existing.raw.fetch("spec", {}).dup
51
+ spec["dependsOn"] = { "applicationComponents" => dep_names }
52
+
53
+ component = {
54
+ "apiVersion" => "architecture/v1alpha1",
55
+ "kind" => "ApplicationComponent",
56
+ "metadata" => {
57
+ "name" => comp_name,
58
+ "annotations" => existing.annotations.merge(
59
+ "generated/script" => import_resource.name,
60
+ "generated/at" => Time.now.utc.iso8601
61
+ )
62
+ },
63
+ "spec" => spec
64
+ }
65
+ output << YAML.dump(component)
66
+ end
67
+
68
+ write_yaml(output + YAML.dump(self_marker))
69
+ end
70
+
71
+ private
72
+
73
+ def compute_deps(mod_dir, mod_name, existing_components)
74
+ prefix = same_origin_prefix(mod_name)
75
+ return [] unless prefix
76
+
77
+ go_mod_requires(mod_dir)
78
+ .select { |r| r.start_with?(prefix) && r != mod_name }
79
+ .filter_map { |r| component_name(r) if existing_components.key?(component_name(r)) }
80
+ .sort.uniq
81
+ end
82
+ end
83
+
84
+ Archsight::Import::Registry.register("go-dep-resolver", Archsight::Import::Handlers::GoDepResolver)
@@ -1,19 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "json"
3
4
  require "open3"
4
- require "find"
5
5
  require_relative "grapher"
6
+ require_relative "go_module_parser"
6
7
  require_relative "../registry"
7
8
 
8
9
  # GoGrapher handler - analyses a Go repository and generates a GraphViz DOT
9
- # graph of its module/package structure, stored as architecture/modules on
10
+ # graph of its module/package structure, stored as architecture/go/modules on
10
11
  # the TechnologyArtifact so it can be rendered in the frontend.
11
12
  #
13
+ # Also emits one ApplicationComponent per go.mod module, linked to the repo
14
+ # artifact via realizedThrough. If OpenAPI spec files are found in a module
15
+ # directory, the component gains an exposes relation to the matching interface.
16
+ #
17
+ # dependsOn relations between components are resolved in a second pass by the
18
+ # GoDepResolver handler, which runs after all graphers have seeded the database.
19
+ #
12
20
  # Configuration:
13
- # import/config/path - Path to the Go repository root (go.mod or go.work)
14
- # import/config/ranksep - Horizontal gap between rank columns (default: 0.6)
15
- # import/config/nodesep - Vertical gap between nodes in a column (default: 0.15)
21
+ # import/config/path - Path to the Go repository root (go.mod or go.work)
22
+ # import/config/ranksep - Horizontal gap between rank columns (default: 0.6)
23
+ # import/config/nodesep - Vertical gap between nodes in a column (default: 0.15)
24
+ # import/config/interface_visibility - Visibility prefix for detected interfaces (default: Private)
16
25
  class Archsight::Import::Handlers::GoGrapher < Archsight::Import::Handlers::Grapher
26
+ include Archsight::Import::Handlers::GoModuleParser
27
+
28
+ OPENAPI_FILENAMES = %w[openapi.yaml openapi.yml openapi.json swagger.yaml swagger.yml swagger.json].freeze
29
+ OPENAPI_SUBDIRS = %w[api docs spec].freeze
30
+
17
31
  def self.language_name = "go"
18
32
 
19
33
  def self.applicable?(path)
@@ -34,56 +48,44 @@ class Archsight::Import::Handlers::GoGrapher < Archsight::Import::Handlers::Grap
34
48
  has_children.include?(dep) && !pkg_set.include?(dep)
35
49
  end
36
50
 
37
- # ── Module discovery ─────────────────────────────────────────────────────
38
-
39
- def discover_modules(repo_root)
40
- work_file = File.join(repo_root, "go.work")
41
- modules = []
42
-
43
- if File.exist?(work_file)
44
- content = File.read(work_file)
45
- dirs = if (block_match = content.match(/\buse\s*\((.*?)\)/m))
46
- block_match[1].split.map(&:strip).reject(&:empty?)
47
- else
48
- content.scan(/\buse\s+(\S+)/).flatten
49
- end
50
- dirs.each do |d|
51
- rel = d == "." ? "" : d.delete_prefix("./")
52
- abs_dir = rel.empty? ? repo_root : File.join(repo_root, rel)
53
- mod_name = read_module_name(abs_dir)
54
- modules << [rel.empty? ? "." : rel, mod_name] if mod_name
55
- end
56
- else
57
- mod_name = read_module_name(repo_root)
58
- if mod_name
59
- modules << [".", mod_name]
60
- else
61
- # No root go.mod: scan subdirectories for go.mod files (monorepo without go.work)
62
- Find.find(repo_root) do |path|
63
- bn = File.basename(path)
64
- Find.prune if File.directory?(path) && %w[vendor testdata .git node_modules].include?(bn)
65
- next unless bn == "go.mod"
66
-
67
- mod_dir = File.dirname(path)
68
- rel = mod_dir.delete_prefix("#{repo_root}/")
69
- name = read_module_name(mod_dir)
70
- modules << [rel, name] if name
71
- end
72
- end
51
+ # ── Application resources ─────────────────────────────────────────────────
52
+
53
+ def additional_resources(path, modules, artifact_name)
54
+ visibility = config("interface_visibility", default: "Private")
55
+ output = +""
56
+
57
+ modules.each do |rel_dir, mod_name|
58
+ mod_dir = rel_dir == "." ? path : File.join(path, rel_dir)
59
+ specs = detect_openapi_specs(mod_dir)
60
+ existing_interfaces = database&.instances_by_kind("ApplicationInterface") || {}
61
+ interface_names = specs.filter_map { |s| interface_name_from_spec(s, visibility: visibility) }
62
+ .select { |n| existing_interfaces.key?(n) }
63
+
64
+ comp_spec = { "realizedThrough" => { "technologyArtifacts" => [artifact_name] } }
65
+ comp_spec["exposes"] = { "applicationInterfaces" => interface_names } if interface_names.any?
66
+
67
+ # Build directly without resource_yaml so the component is not tracked in
68
+ # the generates spec ApplicationComponents are seed resources the user
69
+ # is expected to keep and refine, not auto-regenerated on each run.
70
+ component = untracked_resource_yaml(
71
+ kind: "ApplicationComponent",
72
+ name: component_name(mod_name),
73
+ spec: comp_spec
74
+ )
75
+ output << YAML.dump(component)
73
76
  end
74
77
 
75
- modules
76
- end
77
-
78
- def read_module_name(mod_dir)
79
- gomod = File.join(mod_dir, "go.mod")
80
- return nil unless File.exist?(gomod)
81
-
82
- File.foreach(gomod) do |line|
83
- m = line.match(/^\s*module\s+(\S+)/)
84
- return m[1] if m
85
- end
86
- nil
78
+ # Emit a GoDepResolver import so dependsOn relations can be resolved in a
79
+ # second pass, after all graphers have run and the database has been reloaded
80
+ # with the full set of ApplicationComponents.
81
+ resolver_name = "Import:GoDepResolver:#{artifact_name.delete_prefix("Repo:")}"
82
+ output << YAML.dump(import_yaml(
83
+ name: resolver_name,
84
+ handler: "go-dep-resolver",
85
+ config: { "path" => path }
86
+ ))
87
+
88
+ output
87
89
  end
88
90
 
89
91
  # ── Package collection ────────────────────────────────────────────────────
@@ -93,7 +95,7 @@ class Archsight::Import::Handlers::GoGrapher < Archsight::Import::Handlers::Grap
93
95
  mod_names = modules.map { |_, mod_name| mod_name }
94
96
  all_pkgs = {}
95
97
 
96
- modules.each_key do |rel_dir|
98
+ modules.map(&:first).each do |rel_dir|
97
99
  mod_dir = rel_dir == "." ? repo_root : File.join(repo_root, rel_dir)
98
100
  cmd = ["go", "list", "-e", "-f", "{{.ImportPath}}|||{{join .Imports \" \"}}", "./..."]
99
101
  cmd.insert(2, "-mod=vendor") if File.directory?(File.join(mod_dir, "vendor"))
@@ -122,6 +124,54 @@ class Archsight::Import::Handlers::GoGrapher < Archsight::Import::Handlers::Grap
122
124
 
123
125
  all_pkgs
124
126
  end
127
+
128
+ # ── OpenAPI detection ─────────────────────────────────────────────────────
129
+
130
+ def untracked_resource_yaml(kind:, name:, spec: {})
131
+ {
132
+ "apiVersion" => "architecture/v1alpha1",
133
+ "kind" => kind,
134
+ "metadata" => {
135
+ "name" => name,
136
+ "annotations" => {
137
+ "generated/script" => import_resource.name,
138
+ "generated/at" => Time.now.utc.iso8601
139
+ }
140
+ },
141
+ "spec" => spec
142
+ }
143
+ end
144
+
145
+ def detect_openapi_specs(mod_dir)
146
+ candidates = OPENAPI_FILENAMES.map { |f| File.join(mod_dir, f) }
147
+ OPENAPI_SUBDIRS.each do |sub|
148
+ OPENAPI_FILENAMES.each { |f| candidates << File.join(mod_dir, sub, f) }
149
+ end
150
+
151
+ candidates.filter_map do |path|
152
+ next unless File.file?(path)
153
+
154
+ begin
155
+ content = File.read(path)
156
+ doc = path.end_with?(".json") ? JSON.parse(content) : YAML.safe_load(content)
157
+ doc.is_a?(Hash) ? doc : nil
158
+ rescue StandardError
159
+ nil
160
+ end
161
+ end
162
+ end
163
+
164
+ def interface_name_from_spec(spec, visibility: "Private")
165
+ info = spec["info"] || {}
166
+ title = (info["title"] || "").strip
167
+ return nil if title.empty?
168
+
169
+ version = (info["version"] || "1.0").to_s
170
+ api_name = title.split(/[\s\-_]/).map(&:capitalize).join
171
+ version_str = version.split(".").first.to_s.sub(/^v/i, "")
172
+ vis = visibility.split("-").map(&:capitalize).join
173
+ "#{vis}:#{api_name}:v#{version_str}:RestAPI"
174
+ end
125
175
  end
126
176
 
127
177
  Archsight::Import::Registry.register("go-grapher", Archsight::Import::Handlers::GoGrapher)
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "find"
4
+
5
+ # Shared Go module parsing utilities included by GoGrapher and GoDepResolver.
6
+ #
7
+ # Provides go.mod discovery, module name reading, require parsing, and the
8
+ # component_name convention (strip SCM host, join path segments with ":").
9
+ module Archsight::Import::Handlers::GoModuleParser
10
+ # Discover all Go modules in a repository root.
11
+ # Handles go.work workspaces, single-module repos, and multi-module monorepos
12
+ # (root go.mod plus subdirectory go.mod files without go.work).
13
+ #
14
+ # @param repo_root [String] Absolute path to the repository root
15
+ # @return [Array<Array<String>>] List of [rel_dir, mod_name] pairs
16
+ def discover_modules(repo_root)
17
+ work_file = File.join(repo_root, "go.work")
18
+ modules = []
19
+
20
+ if File.exist?(work_file)
21
+ content = File.read(work_file)
22
+ dirs = if (block_match = content.match(/\buse\s*\((.*?)\)/m))
23
+ block_match[1].split.map(&:strip).reject(&:empty?)
24
+ else
25
+ content.scan(/\buse\s+(\S+)/).flatten
26
+ end
27
+ dirs.each do |d|
28
+ rel = d == "." ? "" : d.delete_prefix("./")
29
+ abs_dir = rel.empty? ? repo_root : File.join(repo_root, rel)
30
+ mod_name = read_module_name(abs_dir)
31
+ modules << [rel.empty? ? "." : rel, mod_name] if mod_name
32
+ end
33
+ else
34
+ root_mod = read_module_name(repo_root)
35
+ modules << [".", root_mod] if root_mod
36
+
37
+ # Also scan subdirectories for additional go.mod files (multi-module monorepo without go.work)
38
+ Find.find(repo_root) do |path|
39
+ bn = File.basename(path)
40
+ Find.prune if File.directory?(path) && %w[vendor testdata .git node_modules].include?(bn)
41
+ next unless bn == "go.mod"
42
+
43
+ mod_dir = File.dirname(path)
44
+ next if mod_dir == repo_root # already added above
45
+
46
+ rel = mod_dir.delete_prefix("#{repo_root}/")
47
+ name = read_module_name(mod_dir)
48
+ modules << [rel, name] if name
49
+ end
50
+ end
51
+
52
+ modules
53
+ end
54
+
55
+ # Read the module name declared in go.mod.
56
+ # @return [String, nil] Module path or nil if go.mod absent / no module line
57
+ def read_module_name(mod_dir)
58
+ gomod = File.join(mod_dir, "go.mod")
59
+ return nil unless File.exist?(gomod)
60
+
61
+ File.foreach(gomod) do |line|
62
+ m = line.match(/^\s*module\s+(\S+)/)
63
+ return m[1] if m
64
+ end
65
+ nil
66
+ end
67
+
68
+ # Parse require directives from go.mod, handling both block and single-line forms.
69
+ # @return [Array<String>] Unique module paths listed in require directives
70
+ def go_mod_requires(mod_dir)
71
+ gomod = File.join(mod_dir, "go.mod")
72
+ return [] unless File.exist?(gomod)
73
+
74
+ content = File.read(gomod)
75
+ paths = []
76
+
77
+ # Block form: require ( ... )
78
+ content.scan(/\brequire\s*\(([^)]*)\)/m) do |block|
79
+ block[0].each_line do |line|
80
+ stripped = line.strip.split("//").first&.strip
81
+ mod_path = stripped&.split&.first
82
+ paths << mod_path if mod_path && !mod_path.empty?
83
+ end
84
+ end
85
+
86
+ # Single-line form: require module/path vX.Y.Z (strip block forms first to avoid double-counting)
87
+ content.gsub(/\brequire\s*\([^)]*\)/m, "").scan(/^\s*require\s+(\S+)/) do |m|
88
+ paths << m[0]
89
+ end
90
+
91
+ paths.uniq
92
+ end
93
+
94
+ # Return the SCM host+org prefix shared by modules in the same org, e.g. "github.com/ionos-cloud/".
95
+ # @return [String, nil] Prefix with trailing slash, or nil for single-segment names
96
+ def same_origin_prefix(mod_name)
97
+ parts = mod_name.split("/")
98
+ return nil if parts.length < 2
99
+
100
+ "#{parts[0, 2].join("/")}/"
101
+ end
102
+
103
+ # Convert a Go module path to an ApplicationComponent name.
104
+ # Strips the SCM host segment and joins remaining path segments with ":".
105
+ # "github.com/ionos-cloud/event-gateway/pkg" → "ionos-cloud:event-gateway:pkg"
106
+ def component_name(mod_name)
107
+ parts = mod_name.split("/")
108
+ parts.shift
109
+ parts.join(":")
110
+ end
111
+ end
@@ -53,6 +53,11 @@ class Archsight::Import::Handlers::Grapher < Archsight::Import::Handler
53
53
  raise "Missing required config: path" unless @path
54
54
  raise "Directory not found: #{@path}" unless File.directory?(@path)
55
55
 
56
+ # Consolidate all grapher output into a single shared file unless an
57
+ # explicit output path is already set (e.g. via grapherOutputPath on the
58
+ # parent Repository import).
59
+ import_resource.annotations["import/outputPath"] ||= "generated/modules.yaml"
60
+
56
61
  @ranksep = config("ranksep", default: "0.6").to_f
57
62
  @nodesep = config("nodesep", default: "0.15").to_f
58
63
 
@@ -71,14 +76,16 @@ class Archsight::Import::Handlers::Grapher < Archsight::Import::Handler
71
76
  ranksep: @ranksep, nodesep: @nodesep)
72
77
 
73
78
  progress.update("Generating resource")
79
+ repo_name = artifact_name(@path)
74
80
  resource = resource_yaml(
75
81
  kind: "TechnologyArtifact",
76
- name: artifact_name(@path),
82
+ name: repo_name,
77
83
  annotations: { annotation_key => dot_content },
78
84
  spec: {}
79
85
  )
80
86
 
81
- write_yaml(YAML.dump(resource) + YAML.dump(self_marker))
87
+ extra = additional_resources(@path, modules, repo_name)
88
+ write_yaml(YAML.dump(resource) + extra + YAML.dump(self_marker))
82
89
  write_generates_meta
83
90
  end
84
91
 
@@ -535,6 +542,12 @@ class Archsight::Import::Handlers::Grapher < Archsight::Import::Handler
535
542
  has_children.include?(dep)
536
543
  end
537
544
 
545
+ # Hook: subclasses may override to emit additional YAML resources (as a
546
+ # concatenated YAML string) alongside the TechnologyArtifact in the output.
547
+ def additional_resources(_path, _modules, _artifact_name)
548
+ ""
549
+ end
550
+
538
551
  # ── Artifact name ─────────────────────────────────────────────────────────
539
552
 
540
553
  def artifact_name(path)
@@ -115,9 +115,12 @@ class Archsight::Import::Handlers::Repository < Archsight::Import::Handler
115
115
  run_git(%w[git fetch --quiet], @path)
116
116
  return if empty_repository? # Skip merge for empty repos
117
117
 
118
- # Check if update is needed
118
+ # FETCH_HEAD may be absent when git fetch brings nothing new (e.g. no
119
+ # tracking refs configured, or the remote has no branches). Skip merge.
120
+ fetch_head = resolve_ref("FETCH_HEAD")
121
+ return unless fetch_head
122
+
119
123
  current_head = run_git(%w[git rev-parse HEAD], @path).strip
120
- fetch_head = run_git(%w[git rev-parse FETCH_HEAD], @path).strip
121
124
  return if current_head == fetch_head # Already up-to-date
122
125
 
123
126
  run_git(%w[git merge --ff-only FETCH_HEAD], @path)
@@ -133,6 +136,11 @@ class Archsight::Import::Handlers::Repository < Archsight::Import::Handler
133
136
  !status.success?
134
137
  end
135
138
 
139
+ def resolve_ref(ref)
140
+ out, _, status = Open3.capture3("git", "rev-parse", ref, chdir: @path)
141
+ status.success? ? out.strip : nil
142
+ end
143
+
136
144
  # Run a git command safely using array form to prevent shell injection
137
145
  # @param command [Array<String>] Command and arguments as array
138
146
  # @param dir [String] Working directory
@@ -44,6 +44,12 @@ class Archsight::Import::Handlers::RestApi < Archsight::Import::Handler
44
44
  progress.update("Downloading OpenAPI spec for #{@name}")
45
45
  openapi_doc = fetch_openapi_spec(@spec_url)
46
46
 
47
+ if openapi_doc.nil?
48
+ progress.warn("Spec not found (404) for #{@name} at #{@spec_url} — skipping")
49
+ write_yaml(YAML.dump(self_marker))
50
+ return
51
+ end
52
+
47
53
  # Parse schemas and generate DataObjects first (needed for interface relations)
48
54
  progress.update("Extracting DataObjects from #{@name} schemas")
49
55
  parser = Archsight::Import::Handlers::OpenAPISchemaParser.new(openapi_doc)
@@ -141,8 +147,9 @@ class Archsight::Import::Handlers::RestApi < Archsight::Import::Handler
141
147
  when Net::HTTPSuccess
142
148
  parse_spec_content(response.body)
143
149
  when Net::HTTPRedirection
144
- # Follow redirect
145
150
  fetch_openapi_spec(response["location"])
151
+ when Net::HTTPNotFound
152
+ nil
146
153
  else
147
154
  raise "Failed to fetch OpenAPI spec from #{uri}: #{response.code} #{response.message}"
148
155
  end
@@ -343,4 +343,5 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
343
343
  relation :servedBy, :technologyComponents, :TechnologySystemSoftware
344
344
  relation :exposes, :applicationInterfaces, :ApplicationInterface
345
345
  relation :dependsOn, :applicationInterfaces, :ApplicationInterface
346
+ relation :dependsOn, :applicationComponents, :ApplicationComponent
346
347
  end
@@ -42,7 +42,10 @@ class Archsight::Resources::Import < Archsight::Resources::Base
42
42
  gitlab github repository
43
43
  rest-api rest-api-index
44
44
  jira-discover jira-metrics
45
- go-grapher
45
+ go-grapher go-dep-resolver
46
+ cpp-grapher ruby-grapher python-grapher
47
+ java-grapher javascript-grapher
48
+ rust-grapher crystal-grapher elixir-grapher
46
49
  ]
47
50
 
48
51
  # Output configuration
@@ -229,7 +229,8 @@ class Archsight::Resources::TechnologyArtifact < Archsight::Resources::Base
229
229
  "go" => "Go", "python" => "Python", "java" => "Java",
230
230
  "typescript" => "TypeScript", "javascript" => "JavaScript",
231
231
  "rust" => "Rust", "ruby" => "Ruby", "crystal" => "Crystal",
232
- "csharp" => "C#", "zig" => "Zig", "elixir" => "Elixir"
232
+ "csharp" => "C#", "zig" => "Zig", "elixir" => "Elixir",
233
+ "cpp" => "C++"
233
234
  }.each do |lang, label|
234
235
  annotation "architecture/#{lang}/modules",
235
236
  description: "GraphViz DOT — #{label} module/package structure",
@@ -4,5 +4,5 @@
4
4
  # Do not edit manually.
5
5
 
6
6
  module Archsight
7
- VERSION = "0.2.5"
7
+ VERSION = "0.2.6"
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: archsight
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vincent Landgraf
@@ -269,7 +269,9 @@ files:
269
269
  - lib/archsight/import/handlers/elixir_grapher.rb
270
270
  - lib/archsight/import/handlers/github.rb
271
271
  - lib/archsight/import/handlers/gitlab.rb
272
+ - lib/archsight/import/handlers/go_dep_resolver.rb
272
273
  - lib/archsight/import/handlers/go_grapher.rb
274
+ - lib/archsight/import/handlers/go_module_parser.rb
273
275
  - lib/archsight/import/handlers/grapher.rb
274
276
  - lib/archsight/import/handlers/java_grapher.rb
275
277
  - lib/archsight/import/handlers/javascript_grapher.rb