archsight 0.2.8 → 0.2.9
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/lib/archsight/import/handler.rb +3 -2
- data/lib/archsight/import/handlers/cache_pruner.rb +23 -0
- data/lib/archsight/import/handlers/github.rb +13 -1
- data/lib/archsight/import/handlers/gitlab.rb +13 -1
- data/lib/archsight/import/handlers/go_module_parser.rb +40 -10
- data/lib/archsight/import/handlers/repository.rb +4 -1
- data/lib/archsight/import/handlers/rest_api_index.rb +20 -2
- data/lib/archsight/import/shared_file_writer.rb +49 -5
- data/lib/archsight/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fca6df89e7a4bbcae73578f3f9bed3bf680dd86561269396a0a4243c84109eed
|
|
4
|
+
data.tar.gz: 3991aafe49e2f950305e91f92cf93c0b953a808647cdceb09ae01edb2df4d304
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e2be76c13cb35664086dc9f5d96675c6c0a54dd11d10803895edac5887428bd7b5d0441c5e419a82454f3532175556c3c398615edabe86b2fe4bf62bc02599b
|
|
7
|
+
data.tar.gz: 42133f269b0f2b09306da83c16fb311539180814e6cec26b3e8bc4f1a4b5b35d08922175f1bf464cd00c6c86f4d7df9931dbf576d00873ca7d174be2459540fe
|
|
@@ -115,7 +115,7 @@ class Archsight::Import::Handler
|
|
|
115
115
|
# Use thread-safe shared writer for concurrent execution
|
|
116
116
|
# Default sort key is import name for stable output ordering
|
|
117
117
|
key = sort_key || import_resource.name
|
|
118
|
-
@shared_writer.append_yaml(full_path, content, sort_key: key)
|
|
118
|
+
@shared_writer.append_yaml(full_path, content, sort_key: key, producer: import_resource.name)
|
|
119
119
|
else
|
|
120
120
|
# Direct write for non-concurrent mode
|
|
121
121
|
FileUtils.mkdir_p(File.dirname(full_path))
|
|
@@ -209,7 +209,8 @@ class Archsight::Import::Handler
|
|
|
209
209
|
end
|
|
210
210
|
|
|
211
211
|
if @shared_writer
|
|
212
|
-
@shared_writer.append_yaml(full_path, YAML.dump(meta), sort_key: "#{import_resource.name}:generates"
|
|
212
|
+
@shared_writer.append_yaml(full_path, YAML.dump(meta), sort_key: "#{import_resource.name}:generates",
|
|
213
|
+
producer: import_resource.name)
|
|
213
214
|
else
|
|
214
215
|
# Append to existing file
|
|
215
216
|
File.open(full_path, "a") { |f| f.write(YAML.dump(meta)) }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Shared helper for import handlers that clone repositories into a local
|
|
4
|
+
# cache directory keyed by name (see github.rb, gitlab.rb). Removes cache
|
|
5
|
+
# subdirectories that no longer correspond to any repo/project returned by
|
|
6
|
+
# the current API listing, so a renamed, moved, or deleted repo doesn't
|
|
7
|
+
# leave a stale clone behind that a later importer could still resolve
|
|
8
|
+
# against under its old name.
|
|
9
|
+
module Archsight::Import::Handlers::CachePruner
|
|
10
|
+
def prune_stale_cache_entries(target_dir, current_names)
|
|
11
|
+
return unless File.directory?(target_dir)
|
|
12
|
+
|
|
13
|
+
Dir.children(target_dir).each do |entry|
|
|
14
|
+
next if current_names.include?(entry)
|
|
15
|
+
|
|
16
|
+
stale_path = File.join(target_dir, entry)
|
|
17
|
+
next unless File.directory?(stale_path)
|
|
18
|
+
|
|
19
|
+
progress.warn("Pruning stale cache entry: #{entry} (repo renamed, moved, or removed)")
|
|
20
|
+
FileUtils.rm_rf(stale_path)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -7,6 +7,7 @@ require "uri"
|
|
|
7
7
|
require "openssl"
|
|
8
8
|
require_relative "../handler"
|
|
9
9
|
require_relative "../registry"
|
|
10
|
+
require_relative "cache_pruner"
|
|
10
11
|
|
|
11
12
|
# GitHub handler - lists repositories from a GitHub organization and generates child Import resources
|
|
12
13
|
#
|
|
@@ -18,6 +19,7 @@ require_relative "../registry"
|
|
|
18
19
|
# import/config/botTeam - Team for bot-only repositories (propagated to child imports)
|
|
19
20
|
# import/config/corporateAffixes - Comma-separated corporate username affixes for team matching (propagated to child imports)
|
|
20
21
|
# import/config/defaultVisibility - Default visibility for non-public repos (default: "internal")
|
|
22
|
+
# import/config/cacheRoot - Override for the local git cache root (default: ~/.cache/archsight/git)
|
|
21
23
|
#
|
|
22
24
|
# Environment:
|
|
23
25
|
# GITHUB_TOKEN - GitHub Personal Access Token (required)
|
|
@@ -27,7 +29,14 @@ require_relative "../registry"
|
|
|
27
29
|
# Output:
|
|
28
30
|
# Generates Import:Repo:* resources for each repository
|
|
29
31
|
# The repository handler will clone/sync the actual git repositories
|
|
32
|
+
#
|
|
33
|
+
# Before generating imports, prunes any cache subdirectory under
|
|
34
|
+
# cacheRoot/github/<org> that no longer corresponds to a repo returned by
|
|
35
|
+
# the API (e.g. a repo that was renamed or deleted), so stale clones don't
|
|
36
|
+
# linger and get picked up by later importers.
|
|
30
37
|
class Archsight::Import::Handlers::Github < Archsight::Import::Handler
|
|
38
|
+
include Archsight::Import::Handlers::CachePruner
|
|
39
|
+
|
|
31
40
|
PER_PAGE = 100
|
|
32
41
|
|
|
33
42
|
def execute
|
|
@@ -40,7 +49,8 @@ class Archsight::Import::Handlers::Github < Archsight::Import::Handler
|
|
|
40
49
|
@repo_output_path = config("repoOutputPath")
|
|
41
50
|
@child_cache_time = config("childCacheTime")
|
|
42
51
|
@default_visibility = config("defaultVisibility", default: "internal")
|
|
43
|
-
|
|
52
|
+
cache_root = config("cacheRoot", default: File.join(Dir.home, ".cache", "archsight", "git"))
|
|
53
|
+
@target_dir = File.join(cache_root, "github", @org)
|
|
44
54
|
|
|
45
55
|
# Fetch all repositories with pagination
|
|
46
56
|
progress.update("Fetching repositories from #{@org}")
|
|
@@ -51,6 +61,8 @@ class Archsight::Import::Handlers::Github < Archsight::Import::Handler
|
|
|
51
61
|
return
|
|
52
62
|
end
|
|
53
63
|
|
|
64
|
+
prune_stale_cache_entries(@target_dir, repos.map { |r| r["name"] })
|
|
65
|
+
|
|
54
66
|
# Generate Import resources for each repository
|
|
55
67
|
progress.update("Generating #{repos.size} import resources")
|
|
56
68
|
generate_repository_imports(repos)
|
|
@@ -8,6 +8,7 @@ require "uri"
|
|
|
8
8
|
require "openssl"
|
|
9
9
|
require_relative "../handler"
|
|
10
10
|
require_relative "../registry"
|
|
11
|
+
require_relative "cache_pruner"
|
|
11
12
|
|
|
12
13
|
# GitLab handler - lists repositories from a GitLab instance and generates child Import resources
|
|
13
14
|
#
|
|
@@ -23,6 +24,7 @@ require_relative "../registry"
|
|
|
23
24
|
# import/config/botTeam - Team for bot-only repositories (propagated to child imports)
|
|
24
25
|
# import/config/corporateAffixes - Comma-separated corporate username affixes for team matching (propagated to child imports)
|
|
25
26
|
# import/config/defaultVisibility - Default visibility when API returns none (default: "internal")
|
|
27
|
+
# import/config/cacheRoot - Override for the local git cache root (default: ~/.cache/archsight/git)
|
|
26
28
|
#
|
|
27
29
|
# Environment:
|
|
28
30
|
# GITLAB_TOKEN - GitLab personal access token (required)
|
|
@@ -30,7 +32,14 @@ require_relative "../registry"
|
|
|
30
32
|
# Output:
|
|
31
33
|
# Generates Import:Repo:* resources for each repository
|
|
32
34
|
# The repository handler will clone/sync the actual git repositories (via SSH)
|
|
35
|
+
#
|
|
36
|
+
# Before generating imports, prunes any cache subdirectory under
|
|
37
|
+
# cacheRoot/gitlab that no longer corresponds to a project returned by the
|
|
38
|
+
# API (e.g. a project that was renamed, moved, or deleted), so stale clones
|
|
39
|
+
# don't linger and get picked up by later importers.
|
|
33
40
|
class Archsight::Import::Handlers::Gitlab < Archsight::Import::Handler
|
|
41
|
+
include Archsight::Import::Handlers::CachePruner
|
|
42
|
+
|
|
34
43
|
def execute
|
|
35
44
|
@host = config("host")
|
|
36
45
|
raise "Missing required config: host" unless @host
|
|
@@ -42,7 +51,8 @@ class Archsight::Import::Handlers::Gitlab < Archsight::Import::Handler
|
|
|
42
51
|
@child_cache_time = config("childCacheTime")
|
|
43
52
|
@default_visibility = config("defaultVisibility", default: "internal")
|
|
44
53
|
|
|
45
|
-
|
|
54
|
+
cache_root = config("cacheRoot", default: File.join(Dir.home, ".cache", "archsight", "git"))
|
|
55
|
+
@target_dir = File.join(cache_root, "gitlab")
|
|
46
56
|
@explore_groups = config("exploreGroups") == "true"
|
|
47
57
|
@per_page = config("perPage", default: "100").to_i
|
|
48
58
|
@verify_ssl = config("verifySSL") != "false"
|
|
@@ -57,6 +67,8 @@ class Archsight::Import::Handlers::Gitlab < Archsight::Import::Handler
|
|
|
57
67
|
return
|
|
58
68
|
end
|
|
59
69
|
|
|
70
|
+
prune_stale_cache_entries(@target_dir, projects.map { |p| safe_dir_name(p["path_with_namespace"]) })
|
|
71
|
+
|
|
60
72
|
# Generate Import resources for each repository
|
|
61
73
|
progress.update("Generating #{projects.size} import resources")
|
|
62
74
|
generate_repository_imports(projects)
|
|
@@ -33,20 +33,41 @@ module Archsight::Import::Handlers::GoModuleParser
|
|
|
33
33
|
else
|
|
34
34
|
root_mod = read_module_name(repo_root)
|
|
35
35
|
modules << [".", root_mod] if root_mod
|
|
36
|
+
modules.concat(discover_nested_modules(repo_root, root_mod))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
modules
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Scan subdirectories for additional go.mod files (multi-module monorepo
|
|
43
|
+
# without go.work). Skips a nested go.mod whose declared module path is
|
|
44
|
+
# unrelated to the repo's own root module - likely a vendored/embedded copy
|
|
45
|
+
# of a foreign project (e.g. a full committed snapshot of another,
|
|
46
|
+
# possibly since-renamed, repo) rather than an intentional submodule of
|
|
47
|
+
# this one - so it doesn't manufacture a cross-repo component/dependency.
|
|
48
|
+
#
|
|
49
|
+
# @return [Array<Array<String>>] List of [rel_dir, mod_name] pairs
|
|
50
|
+
def discover_nested_modules(repo_root, root_mod)
|
|
51
|
+
modules = []
|
|
52
|
+
|
|
53
|
+
Find.find(repo_root) do |path|
|
|
54
|
+
bn = File.basename(path)
|
|
55
|
+
Find.prune if File.directory?(path) && %w[vendor testdata .git node_modules].include?(bn)
|
|
56
|
+
next unless bn == "go.mod"
|
|
36
57
|
|
|
37
|
-
|
|
38
|
-
|
|
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"
|
|
58
|
+
mod_dir = File.dirname(path)
|
|
59
|
+
next if mod_dir == repo_root # already added above
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
rel = mod_dir.delete_prefix("#{repo_root}/")
|
|
62
|
+
name = read_module_name(mod_dir)
|
|
63
|
+
next unless name
|
|
45
64
|
|
|
46
|
-
|
|
47
|
-
name
|
|
48
|
-
|
|
65
|
+
if root_mod && !nested_under_root?(name, root_mod)
|
|
66
|
+
progress.warn("Skipping foreign nested go.mod at #{rel}: module #{name} is unrelated to root module #{root_mod}")
|
|
67
|
+
next
|
|
49
68
|
end
|
|
69
|
+
|
|
70
|
+
modules << [rel, name]
|
|
50
71
|
end
|
|
51
72
|
|
|
52
73
|
modules
|
|
@@ -91,6 +112,15 @@ module Archsight::Import::Handlers::GoModuleParser
|
|
|
91
112
|
paths.uniq
|
|
92
113
|
end
|
|
93
114
|
|
|
115
|
+
# Whether a nested module's declared path is the root module itself or
|
|
116
|
+
# genuinely nested under it (a real monorepo submodule), as opposed to an
|
|
117
|
+
# unrelated/foreign module path (a vendored or embedded copy of another
|
|
118
|
+
# project) that happens to live in a subdirectory.
|
|
119
|
+
# @return [Boolean]
|
|
120
|
+
def nested_under_root?(mod_name, root_mod_name)
|
|
121
|
+
mod_name == root_mod_name || mod_name.start_with?("#{root_mod_name}/")
|
|
122
|
+
end
|
|
123
|
+
|
|
94
124
|
# Return the SCM host+org prefix shared by modules in the same org, e.g. "github.com/ionos-cloud/".
|
|
95
125
|
# @return [String, nil] Prefix with trailing slash, or nil for single-segment names
|
|
96
126
|
def same_origin_prefix(mod_name)
|
|
@@ -227,7 +227,10 @@ class Archsight::Import::Handlers::Repository < Archsight::Import::Handler
|
|
|
227
227
|
private
|
|
228
228
|
|
|
229
229
|
def run_scc(path)
|
|
230
|
-
|
|
230
|
+
# Plain Text files (.txt, .text) are excluded: they carry no structural code
|
|
231
|
+
# signal and can dominate scc's cost/effort estimates when a repo happens to
|
|
232
|
+
# contain large ad hoc text blobs (e.g. datasets, doc dumps).
|
|
233
|
+
cmd = ["scc", "--exclude-dir", ".git,.hg,.svn,vendor,node_modules", "-x", "txt,text", "-f", "json2", "--sort", "name", path]
|
|
231
234
|
|
|
232
235
|
out, err, status = Open3.capture3(*cmd)
|
|
233
236
|
raise "scc failed: #{cmd.join(" ")}\n#{err}" unless status.success?
|
|
@@ -21,6 +21,9 @@ require_relative "../registry"
|
|
|
21
21
|
# APIs whose "gate" value isn't a recognized status (General-Availability,
|
|
22
22
|
# Early-Access, Development, or their GA/EA/DEV aliases) are skipped, since
|
|
23
23
|
# they can't be represented by the ApplicationInterface status annotation.
|
|
24
|
+
# A gate value that embeds a recognized GA/EA/DEV token alongside extra
|
|
25
|
+
# segments (e.g. "ea.ionosc") is tolerated by extracting that token instead
|
|
26
|
+
# of being rejected outright.
|
|
24
27
|
#
|
|
25
28
|
# Output:
|
|
26
29
|
# Generates Import:RestApi:* resources for each API in the index
|
|
@@ -41,6 +44,7 @@ require_relative "../registry"
|
|
|
41
44
|
# }
|
|
42
45
|
class Archsight::Import::Handlers::RestApiIndex < Archsight::Import::Handler
|
|
43
46
|
VALID_GATES = %w[General-Availability Early-Access Development GA EA DEV].freeze
|
|
47
|
+
GATE_TOKEN_RE = /\b(ga|ea|dev)\b/i
|
|
44
48
|
|
|
45
49
|
def execute
|
|
46
50
|
@index_url = config("indexUrl")
|
|
@@ -123,7 +127,21 @@ class Archsight::Import::Handlers::RestApiIndex < Archsight::Import::Handler
|
|
|
123
127
|
def valid_gate?(gate)
|
|
124
128
|
return true if gate.nil? # falls back to "GA" default in generate_api_imports
|
|
125
129
|
|
|
126
|
-
|
|
130
|
+
!resolve_gate(gate).nil?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Resolve a gate value to a recognized stage (a VALID_GATES entry, matched
|
|
134
|
+
# as given, or an extracted GA/EA/DEV token), tolerating extra trailing
|
|
135
|
+
# segments some index entries carry (e.g. an "ionosc" variant suffix like
|
|
136
|
+
# "ea.ionosc") by pulling the first recognized stage token out of an
|
|
137
|
+
# otherwise-unrecognized value rather than rejecting it outright.
|
|
138
|
+
# @return [String, nil] Resolved gate, or nil if no recognized stage found
|
|
139
|
+
def resolve_gate(gate)
|
|
140
|
+
return nil if gate.nil?
|
|
141
|
+
return gate if VALID_GATES.any? { |valid| gate.casecmp?(valid) }
|
|
142
|
+
|
|
143
|
+
match = GATE_TOKEN_RE.match(gate)
|
|
144
|
+
match && match[1].upcase
|
|
127
145
|
end
|
|
128
146
|
|
|
129
147
|
def generate_api_imports(apis)
|
|
@@ -148,7 +166,7 @@ class Archsight::Import::Handlers::RestApiIndex < Archsight::Import::Handler
|
|
|
148
166
|
"version" => api["version"] || "1.0",
|
|
149
167
|
"visibility" => visibility,
|
|
150
168
|
"specUrl" => spec_url,
|
|
151
|
-
"gate" => api["gate"] || "GA"
|
|
169
|
+
"gate" => resolve_gate(api["gate"]) || "GA"
|
|
152
170
|
}
|
|
153
171
|
child_config["htmlUrl"] = html_url if html_url
|
|
154
172
|
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "fileutils"
|
|
4
|
+
require "yaml"
|
|
4
5
|
|
|
5
6
|
# Thread-safe file writer for concurrent import handlers
|
|
6
7
|
#
|
|
7
8
|
# Manages shared output files that multiple handlers can write to.
|
|
8
9
|
# Content is buffered in memory and sorted by key when close_all is called.
|
|
9
10
|
#
|
|
11
|
+
# When a file is flushed, any document already on disk whose producer isn't
|
|
12
|
+
# among this flush's fresh producers is carried forward unchanged - this is
|
|
13
|
+
# what lets a cached (skipped) import's previously-generated output, or
|
|
14
|
+
# another task's output from an earlier iteration of the same run, survive
|
|
15
|
+
# being flushed to a shared output file instead of getting silently wiped.
|
|
16
|
+
#
|
|
10
17
|
# @example
|
|
11
18
|
# writer = SharedFileWriter.new
|
|
12
|
-
# writer.append_yaml("/path/to/output.yaml", yaml_content, sort_key: "Repo:name")
|
|
13
|
-
# writer.close_all # Sorts and writes buffered content
|
|
19
|
+
# writer.append_yaml("/path/to/output.yaml", yaml_content, sort_key: "Repo:name", producer: "Import:Repo:name")
|
|
20
|
+
# writer.close_all # Sorts and writes buffered content, merged with existing content
|
|
14
21
|
class Archsight::Import::SharedFileWriter
|
|
15
22
|
def initialize
|
|
16
23
|
@mutex = Mutex.new
|
|
@@ -23,14 +30,17 @@ class Archsight::Import::SharedFileWriter
|
|
|
23
30
|
# @param path [String] Full path to the output file
|
|
24
31
|
# @param content [String] YAML content to append
|
|
25
32
|
# @param sort_key [String, nil] Key for sorting (nil keys go last)
|
|
26
|
-
|
|
33
|
+
# @param producer [String, nil] Name of the Import task that produced this
|
|
34
|
+
# content, used to decide what existing on-disk content this entry may
|
|
35
|
+
# supersede when the file is flushed
|
|
36
|
+
def append_yaml(path, content, sort_key: nil, producer: nil)
|
|
27
37
|
@mutex.synchronize do
|
|
28
38
|
@files[path] ||= { entries: [], lock: Mutex.new }
|
|
29
39
|
end
|
|
30
40
|
|
|
31
41
|
entry = @files[path]
|
|
32
42
|
entry[:lock].synchronize do
|
|
33
|
-
entry[:entries] << { key: sort_key, content: content }
|
|
43
|
+
entry[:entries] << { key: sort_key, content: content, producer: producer }
|
|
34
44
|
end
|
|
35
45
|
end
|
|
36
46
|
|
|
@@ -51,8 +61,11 @@ class Archsight::Import::SharedFileWriter
|
|
|
51
61
|
|
|
52
62
|
FileUtils.mkdir_p(File.dirname(path))
|
|
53
63
|
|
|
64
|
+
fresh_producers = entries.filter_map { |e| e[:producer] }.uniq
|
|
65
|
+
all_entries = preserved_entries(path, fresh_producers) + entries
|
|
66
|
+
|
|
54
67
|
# Sort by key (nil keys go last)
|
|
55
|
-
sorted =
|
|
68
|
+
sorted = all_entries.sort_by { |e| e[:key] || "\xFF" }
|
|
56
69
|
|
|
57
70
|
File.open(path, "w") do |file|
|
|
58
71
|
sorted.each_with_index do |entry, idx|
|
|
@@ -64,4 +77,35 @@ class Archsight::Import::SharedFileWriter
|
|
|
64
77
|
end
|
|
65
78
|
end
|
|
66
79
|
end
|
|
80
|
+
|
|
81
|
+
# Documents already on disk whose producer isn't among this flush's fresh
|
|
82
|
+
# producers are carried forward unchanged, keyed by their own producer so
|
|
83
|
+
# a producer that does write fresh content later in the same run replaces
|
|
84
|
+
# its own prior output rather than duplicating it. Content is kept as its
|
|
85
|
+
# original raw text (not re-dumped), so anything preserved is byte-for-byte
|
|
86
|
+
# identical to what was already on disk.
|
|
87
|
+
def preserved_entries(path, fresh_producers)
|
|
88
|
+
return [] unless File.exist?(path)
|
|
89
|
+
|
|
90
|
+
split_yaml_documents(File.read(path)).filter_map do |raw|
|
|
91
|
+
doc = YAML.safe_load(raw, permitted_classes: [Time])
|
|
92
|
+
next nil unless doc.is_a?(Hash)
|
|
93
|
+
|
|
94
|
+
producer = document_producer(doc)
|
|
95
|
+
next nil if producer.nil? || fresh_producers.include?(producer)
|
|
96
|
+
|
|
97
|
+
{ key: producer, content: raw, producer: producer }
|
|
98
|
+
rescue Psych::SyntaxError
|
|
99
|
+
nil
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def document_producer(doc)
|
|
104
|
+
doc.dig("metadata", "annotations", "generated/script") ||
|
|
105
|
+
(doc["kind"] == "Import" ? doc.dig("metadata", "name") : nil)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def split_yaml_documents(text)
|
|
109
|
+
text.split(/^---\s*$/).map(&:strip).reject(&:empty?)
|
|
110
|
+
end
|
|
67
111
|
end
|
data/lib/archsight/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.2.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vincent Landgraf
|
|
@@ -264,6 +264,7 @@ files:
|
|
|
264
264
|
- lib/archsight/import/executor.rb
|
|
265
265
|
- lib/archsight/import/git_analytics.rb
|
|
266
266
|
- lib/archsight/import/handler.rb
|
|
267
|
+
- lib/archsight/import/handlers/cache_pruner.rb
|
|
267
268
|
- lib/archsight/import/handlers/cpp_grapher.rb
|
|
268
269
|
- lib/archsight/import/handlers/crystal_grapher.rb
|
|
269
270
|
- lib/archsight/import/handlers/elixir_grapher.rb
|