archsight 0.1.2 → 0.1.3

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -5
  3. data/lib/archsight/analysis/executor.rb +112 -0
  4. data/lib/archsight/analysis/result.rb +174 -0
  5. data/lib/archsight/analysis/sandbox.rb +319 -0
  6. data/lib/archsight/analysis.rb +11 -0
  7. data/lib/archsight/annotations/architecture_annotations.rb +2 -2
  8. data/lib/archsight/cli.rb +163 -0
  9. data/lib/archsight/database.rb +6 -2
  10. data/lib/archsight/helpers/analysis_renderer.rb +83 -0
  11. data/lib/archsight/helpers/formatting.rb +95 -0
  12. data/lib/archsight/helpers.rb +20 -4
  13. data/lib/archsight/import/concurrent_progress.rb +341 -0
  14. data/lib/archsight/import/executor.rb +466 -0
  15. data/lib/archsight/import/git_analytics.rb +626 -0
  16. data/lib/archsight/import/handler.rb +263 -0
  17. data/lib/archsight/import/handlers/github.rb +161 -0
  18. data/lib/archsight/import/handlers/gitlab.rb +202 -0
  19. data/lib/archsight/import/handlers/jira_base.rb +189 -0
  20. data/lib/archsight/import/handlers/jira_discover.rb +161 -0
  21. data/lib/archsight/import/handlers/jira_metrics.rb +179 -0
  22. data/lib/archsight/import/handlers/openapi_schema_parser.rb +279 -0
  23. data/lib/archsight/import/handlers/repository.rb +439 -0
  24. data/lib/archsight/import/handlers/rest_api.rb +293 -0
  25. data/lib/archsight/import/handlers/rest_api_index.rb +183 -0
  26. data/lib/archsight/import/progress.rb +91 -0
  27. data/lib/archsight/import/registry.rb +54 -0
  28. data/lib/archsight/import/shared_file_writer.rb +67 -0
  29. data/lib/archsight/import/team_matcher.rb +195 -0
  30. data/lib/archsight/import.rb +14 -0
  31. data/lib/archsight/resources/analysis.rb +91 -0
  32. data/lib/archsight/resources/application_component.rb +2 -2
  33. data/lib/archsight/resources/application_service.rb +12 -12
  34. data/lib/archsight/resources/business_product.rb +12 -12
  35. data/lib/archsight/resources/data_object.rb +1 -1
  36. data/lib/archsight/resources/import.rb +79 -0
  37. data/lib/archsight/resources/technology_artifact.rb +23 -2
  38. data/lib/archsight/version.rb +1 -1
  39. data/lib/archsight/web/api/docs.rb +17 -0
  40. data/lib/archsight/web/api/json_helpers.rb +164 -0
  41. data/lib/archsight/web/api/openapi/spec.yaml +500 -0
  42. data/lib/archsight/web/api/routes.rb +101 -0
  43. data/lib/archsight/web/application.rb +66 -43
  44. data/lib/archsight/web/doc/import.md +458 -0
  45. data/lib/archsight/web/doc/index.md.erb +1 -0
  46. data/lib/archsight/web/public/css/artifact.css +10 -0
  47. data/lib/archsight/web/public/css/graph.css +14 -0
  48. data/lib/archsight/web/public/css/instance.css +489 -0
  49. data/lib/archsight/web/views/api_docs.erb +19 -0
  50. data/lib/archsight/web/views/partials/artifact/_project_estimate.haml +14 -8
  51. data/lib/archsight/web/views/partials/instance/_analysis_detail.haml +74 -0
  52. data/lib/archsight/web/views/partials/instance/_analysis_result.haml +64 -0
  53. data/lib/archsight/web/views/partials/instance/_detail.haml +7 -3
  54. data/lib/archsight/web/views/partials/instance/_import_detail.haml +87 -0
  55. data/lib/archsight/web/views/partials/instance/_relations.haml +4 -4
  56. data/lib/archsight/web/views/partials/layout/_content.haml +4 -0
  57. data/lib/archsight/web/views/partials/layout/_navigation.haml +6 -5
  58. metadata +78 -1
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "archsight/import"
4
+
5
+ # Matches git contributors to BusinessActor teams
6
+ #
7
+ # Uses team member email and name patterns from BusinessActor annotations
8
+ # to match top contributors from git history to teams.
9
+ #
10
+ # @example
11
+ # matcher = Archsight::Import::TeamMatcher.new(database)
12
+ # result = matcher.analyze(top_contributors)
13
+ # # => { maintainer: "Team:Engineering", contributors: ["Team:QA", "Team:Ops"] }
14
+ class Archsight::Import::TeamMatcher
15
+ # Teams to ignore when matching (bots, unknown, etc.)
16
+ IGNORED_TEAMS = %w[Bot:Team No:Team Team:Unknown Team:Bot].freeze
17
+
18
+ def initialize(database)
19
+ @database = database
20
+ @teams = load_teams
21
+ @email_to_team = build_email_index
22
+ @name_to_team = build_name_index
23
+ end
24
+
25
+ # Analyze top contributors and return team assignments
26
+ #
27
+ # @param top_contributors [Array<Hash>] List of contributors with "name", "email", "commits" keys
28
+ # @return [Hash] { maintainer: String?, contributors: [String] }
29
+ def analyze(top_contributors)
30
+ return { maintainer: nil, contributors: [] } if top_contributors.nil? || top_contributors.empty?
31
+
32
+ team_commits = Hash.new(0)
33
+
34
+ top_contributors.each do |contributor|
35
+ team = match_contributor(contributor["name"], contributor["email"])
36
+ next unless team
37
+ next if IGNORED_TEAMS.include?(team)
38
+
39
+ team_commits[team] += contributor["commits"]
40
+ end
41
+
42
+ return { maintainer: nil, contributors: [] } if team_commits.empty?
43
+
44
+ # Sort by commits descending
45
+ sorted = team_commits.sort_by { |_, commits| -commits }
46
+
47
+ {
48
+ maintainer: sorted.first&.first,
49
+ contributors: sorted.drop(1).map(&:first)
50
+ }
51
+ end
52
+
53
+ # Match a single contributor to a team
54
+ #
55
+ # @param name [String] Contributor name
56
+ # @param email [String] Contributor email
57
+ # @return [String, nil] Team name or nil if no match
58
+ def match_contributor(name, email)
59
+ return nil if name.nil? && email.nil?
60
+
61
+ # Try exact email match first (most reliable)
62
+ if email
63
+ normalized_email = email.to_s.downcase.strip
64
+ team = @email_to_team[normalized_email]
65
+ return team if team
66
+ end
67
+
68
+ # Try name match (less reliable, but useful for LDAP-style names)
69
+ if name
70
+ normalized_name = normalize_name(name)
71
+ team = @name_to_team[normalized_name]
72
+ return team if team
73
+ end
74
+
75
+ nil
76
+ end
77
+
78
+ private
79
+
80
+ def load_teams
81
+ return {} unless @database
82
+
83
+ begin
84
+ @database.instances_by_kind("BusinessActor")&.values || []
85
+ rescue StandardError
86
+ []
87
+ end
88
+ end
89
+
90
+ def build_email_index
91
+ index = {}
92
+
93
+ @teams.each do |team|
94
+ team_name = team.name
95
+
96
+ # Extract emails from team/members annotation
97
+ members = team.annotations["team/members"]
98
+ parse_email_list(members).each do |email|
99
+ index[email.downcase] = team_name
100
+ end
101
+
102
+ # Extract email from team/lead annotation
103
+ lead = team.annotations["team/lead"]
104
+ parse_email_list(lead).each do |email|
105
+ index[email.downcase] = team_name
106
+ end
107
+ end
108
+
109
+ index
110
+ end
111
+
112
+ def build_name_index
113
+ index = {}
114
+
115
+ @teams.each do |team|
116
+ team_name = team.name
117
+
118
+ # Extract names from team/members annotation
119
+ members = team.annotations["team/members"]
120
+ parse_name_list(members).each do |name|
121
+ normalized = normalize_name(name)
122
+ index[normalized] = team_name if normalized && !normalized.empty?
123
+ end
124
+
125
+ # Extract name from team/lead annotation
126
+ lead = team.annotations["team/lead"]
127
+ parse_name_list(lead).each do |name|
128
+ normalized = normalize_name(name)
129
+ index[normalized] = team_name if normalized && !normalized.empty?
130
+ end
131
+ end
132
+
133
+ index
134
+ end
135
+
136
+ # Parse email addresses from team annotation
137
+ # Supports formats: "Name <email>", "email", or comma/newline separated lists
138
+ def parse_email_list(value)
139
+ return [] if value.nil? || value.empty?
140
+
141
+ emails = []
142
+
143
+ # Split by comma or newline
144
+ value.split(/[,\n]/).each do |entry|
145
+ entry = entry.strip
146
+ next if entry.empty?
147
+
148
+ # Try to extract email from "Name <email>" format
149
+ if (match = entry.match(/<([^>]+)>/))
150
+ emails << match[1].strip
151
+ elsif entry.include?("@")
152
+ # Plain email address
153
+ emails << entry
154
+ end
155
+ end
156
+
157
+ emails
158
+ end
159
+
160
+ # Parse names from team annotation
161
+ # Supports formats: "Name <email>", "First Last", or comma/newline separated lists
162
+ def parse_name_list(value)
163
+ return [] if value.nil? || value.empty?
164
+
165
+ names = []
166
+
167
+ # Split by comma or newline
168
+ value.split(/[,\n]/).each do |entry|
169
+ entry = entry.strip
170
+ next if entry.empty?
171
+
172
+ # Try to extract name from "Name <email>" format
173
+ if (match = entry.match(/^([^<]+)</))
174
+ name = match[1].strip
175
+ names << name unless name.empty?
176
+ elsif !entry.include?("@")
177
+ # Plain name (no email)
178
+ names << entry
179
+ end
180
+ end
181
+
182
+ names
183
+ end
184
+
185
+ # Normalize name for matching
186
+ # Converts to lowercase, removes extra spaces, handles common variations
187
+ def normalize_name(name)
188
+ return nil if name.nil?
189
+
190
+ name.to_s
191
+ .downcase
192
+ .gsub(/\s+/, " ")
193
+ .strip
194
+ end
195
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Define import module namespaces
4
+ module Archsight
5
+ module Import
6
+ module Handlers
7
+ end
8
+ end
9
+ end
10
+
11
+ require_relative "import/registry"
12
+ require_relative "import/handler"
13
+ require_relative "import/executor"
14
+ # Handlers are loaded by CLI's require_import_handlers method
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Analysis represents a declarative analysis script that validates or reports on architecture resources
4
+ class Archsight::Resources::Analysis < Archsight::Resources::Base
5
+ include_annotations :generated
6
+
7
+ description <<~MD
8
+ Represents a declarative analysis script for validating or reporting on architecture resources.
9
+
10
+ ## Definition
11
+
12
+ An Analysis is a tool-specific resource type that defines Ruby scripts to run
13
+ against the architecture database. Scripts execute in a sandboxed environment
14
+ with access to instance traversal, annotation access, and reporting methods.
15
+
16
+ ## Usage
17
+
18
+ Use Analysis to represent:
19
+
20
+ - Validation rules (team ownership, naming conventions)
21
+ - Architecture compliance checks
22
+ - Metrics collection and aggregation
23
+ - Custom reports and dashboards
24
+
25
+ ## Script Environment
26
+
27
+ Scripts have access to:
28
+
29
+ - `each_instance(kind)` - iterate over all instances of a kind
30
+ - `instances(kind)` - get array of instances
31
+ - `instance(kind, name)` - get specific instance
32
+ - `outgoing(inst, kind)` / `incoming(inst, kind)` - relation traversal
33
+ - `outgoing_transitive(inst, kind)` / `incoming_transitive(inst, kind)` - transitive relations
34
+ - `annotation(inst, key)` - get annotation value
35
+ - `name(inst)` / `kind(inst)` - get instance metadata
36
+ - `query(query_string)` - execute a query
37
+ - `report(data, title:)` - output findings
38
+ - `warning(msg)` / `error(msg)` / `info(msg)` - log messages
39
+ MD
40
+
41
+ icon "clipboard-check"
42
+ layer "other"
43
+
44
+ # Handler selection (for future extensibility)
45
+ annotation "analysis/handler",
46
+ description: "Script handler type (only 'ruby' currently supported)",
47
+ title: "Handler",
48
+ enum: %w[ruby]
49
+
50
+ # Script content
51
+ annotation "analysis/script",
52
+ description: "Ruby script to execute in sandboxed environment",
53
+ title: "Script",
54
+ sidebar: false
55
+
56
+ # Description
57
+ annotation "analysis/description",
58
+ description: "Human-readable description of what this analysis validates",
59
+ title: "Description"
60
+
61
+ # Execution configuration
62
+ annotation "analysis/timeout",
63
+ description: "Maximum execution time (e.g., '30s', '5m')",
64
+ title: "Timeout"
65
+
66
+ # Output configuration
67
+ annotation "analysis/output",
68
+ description: "Output mode for results",
69
+ title: "Output",
70
+ enum: %w[console file]
71
+
72
+ annotation "analysis/outputPath",
73
+ description: "File path for output (when output mode is 'file')",
74
+ title: "Output Path",
75
+ sidebar: false
76
+
77
+ # Enabled flag
78
+ annotation "analysis/enabled",
79
+ description: "Whether this analysis is enabled",
80
+ title: "Enabled",
81
+ enum: %w[true false]
82
+
83
+ # Pattern annotation for custom configuration
84
+ annotation "analysis/config/*",
85
+ description: "Custom configuration values for the analysis script",
86
+ sidebar: false
87
+
88
+ # Dependency relation (analyses can depend on other analyses or imports)
89
+ relation :dependsOn, :imports, :Import
90
+ relation :dependsOn, :analyses, :Analysis
91
+ end
@@ -182,9 +182,9 @@ class Archsight::Resources::ApplicationComponent < Archsight::Resources::Base
182
182
  %w[scc/estimatedCost scc/estimatedScheduleMonths scc/estimatedPeople].each do |anno_key|
183
183
  computed_annotation anno_key,
184
184
  title: "Total #{anno_key.split("/").last.split(/(?=[A-Z])/).map(&:capitalize).join(" ")}",
185
- description: "Total estimated #{anno_key.split("/").last} from related artifacts",
185
+ description: "Total estimated #{anno_key.split("/").last} from related repositories",
186
186
  type: Integer do
187
- sum(outgoing_transitive(:TechnologyArtifact), anno_key)
187
+ sum(outgoing_transitive('TechnologyArtifact: artifact/type == "repo"'), anno_key)
188
188
  end
189
189
  end
190
190
 
@@ -39,45 +39,45 @@ class Archsight::Resources::ApplicationService < Archsight::Resources::Base
39
39
  # Computed Annotations
40
40
  computed_annotation "repository/artifacts/total",
41
41
  title: "Total Git Repositories",
42
- description: "Number of related git repositories across all related application components",
42
+ description: "Number of related git repositories",
43
43
  type: Integer do
44
- sum(outgoing_transitive(:ApplicationComponent), "repository/artifacts/total")
44
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo"'))
45
45
  end
46
46
 
47
47
  computed_annotation "repository/artifacts/active",
48
48
  title: "Active Git Repositories",
49
- description: "Number of related git repositories across all related application components",
49
+ description: "Number of active git repositories",
50
50
  type: Integer do
51
- sum(outgoing_transitive(:ApplicationComponent), "repository/artifacts/active")
51
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "active"'))
52
52
  end
53
53
 
54
54
  computed_annotation "repository/artifacts/abandoned",
55
55
  title: "Abandoned Git Repositories",
56
- description: "Number of related git repositories across all related application components",
56
+ description: "Number of abandoned git repositories",
57
57
  type: Integer do
58
- sum(outgoing_transitive(:ApplicationComponent), "repository/artifacts/abandoned")
58
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "abandoned"'))
59
59
  end
60
60
 
61
61
  computed_annotation "repository/artifacts/highBusFactor",
62
62
  title: "High Bus Factor Repositories",
63
- description: "Number of active git repositories with high bus factor across all related application components",
63
+ description: "Number of active git repositories with high bus factor",
64
64
  type: Integer do
65
- sum(outgoing_transitive(:ApplicationComponent), "repository/artifacts/highBusFactor")
65
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo" & activity/busFactor == "high"'))
66
66
  end
67
67
 
68
68
  computed_annotation "repository/artifacts/archived",
69
69
  title: "Archived Repositories",
70
- description: "Number of archived git repositories across all related application components",
70
+ description: "Number of archived git repositories",
71
71
  type: Integer do
72
- sum(outgoing_transitive(:ApplicationComponent), "repository/artifacts/archived")
72
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "archived"'))
73
73
  end
74
74
 
75
75
  %w[scc/estimatedCost scc/estimatedScheduleMonths scc/estimatedPeople].each do |anno_key|
76
76
  computed_annotation anno_key,
77
77
  title: "Total #{anno_key.split("/").last.split(/(?=[A-Z])/).map(&:capitalize).join(" ")}",
78
- description: "Total estimated #{anno_key.split("/").last} from related artifacts across all related application components",
78
+ description: "Total estimated #{anno_key.split("/").last} from related repositories",
79
79
  type: Integer do
80
- sum(outgoing_transitive(:ApplicationComponent), anno_key)
80
+ sum(outgoing_transitive('TechnologyArtifact: artifact/type == "repo"'), anno_key)
81
81
  end
82
82
  end
83
83
 
@@ -32,45 +32,45 @@ class Archsight::Resources::BusinessProduct < Archsight::Resources::Base
32
32
 
33
33
  computed_annotation "repository/artifacts/total",
34
34
  title: "Total Git Repositories",
35
- description: "Number of related git repositories across all related application components",
35
+ description: "Number of related git repositories",
36
36
  type: Integer do
37
- sum(outgoing_transitive(:ApplicationService), "repository/artifacts/total")
37
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo"'))
38
38
  end
39
39
 
40
40
  computed_annotation "repository/artifacts/active",
41
41
  title: "Active Git Repositories",
42
- description: "Number of related git repositories across all related application components",
42
+ description: "Number of active git repositories",
43
43
  type: Integer do
44
- sum(outgoing_transitive(:ApplicationService), "repository/artifacts/active")
44
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "active"'))
45
45
  end
46
46
 
47
47
  computed_annotation "repository/artifacts/abandoned",
48
48
  title: "Abandoned Git Repositories",
49
- description: "Number of related git repositories across all related application components",
49
+ description: "Number of abandoned git repositories",
50
50
  type: Integer do
51
- sum(outgoing_transitive(:ApplicationService), "repository/artifacts/abandoned")
51
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "abandoned"'))
52
52
  end
53
53
 
54
54
  computed_annotation "repository/artifacts/highBusFactor",
55
55
  title: "High Bus Factor Repositories",
56
- description: "Number of active git repositories with high bus factor across all related application components",
56
+ description: "Number of active git repositories with high bus factor",
57
57
  type: Integer do
58
- sum(outgoing_transitive(:ApplicationService), "repository/artifacts/highBusFactor")
58
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo" & activity/busFactor == "high"'))
59
59
  end
60
60
 
61
61
  computed_annotation "repository/artifacts/archived",
62
62
  title: "Archived Repositories",
63
- description: "Number of archived git repositories across all related application services",
63
+ description: "Number of archived git repositories",
64
64
  type: Integer do
65
- sum(outgoing_transitive(:ApplicationService), "repository/artifacts/archived")
65
+ count(outgoing_transitive('TechnologyArtifact: artifact/type == "repo" & activity/status == "archived"'))
66
66
  end
67
67
 
68
68
  %w[scc/estimatedCost scc/estimatedScheduleMonths scc/estimatedPeople].each do |anno_key|
69
69
  computed_annotation anno_key,
70
70
  title: "Total #{anno_key.split("/").last.split(/(?=[A-Z])/).map(&:capitalize).join(" ")}",
71
- description: "Total estimated #{anno_key.split("/").last} from related artifacts across all related application components",
71
+ description: "Total estimated #{anno_key.split("/").last} from related repositories",
72
72
  type: Integer do
73
- sum(outgoing_transitive(:ApplicationService), anno_key)
73
+ sum(outgoing_transitive('TechnologyArtifact: artifact/type == "repo"'), anno_key)
74
74
  end
75
75
  end
76
76
 
@@ -38,7 +38,7 @@ 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]
41
+ enum: %w[public private internal]
42
42
 
43
43
  annotation "generated/variants",
44
44
  description: "OpenAPI schema variants compacted into this DataObject",
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Import represents a data import task that generates architecture resources
4
+ class Archsight::Resources::Import < Archsight::Resources::Base
5
+ include_annotations :generated
6
+
7
+ description <<~MD
8
+ Represents an import task that generates architecture resources.
9
+
10
+ ## Definition
11
+
12
+ An Import is a tool-specific resource type that defines how to synchronize
13
+ external data sources (GitLab, GitHub, ArgoCD, etc.) into the architecture
14
+ database. Imports can depend on other imports to ensure proper execution order.
15
+
16
+ ## Usage
17
+
18
+ Use Import to represent:
19
+
20
+ - Repository synchronization tasks
21
+ - API data imports
22
+ - Cluster discovery
23
+ - External system integration
24
+
25
+ ## Multi-Stage Imports
26
+
27
+ Imports can generate other Import resources, enabling multi-stage workflows:
28
+
29
+ 1. GitLab import runs, discovers repositories
30
+ 2. Generates Import resources for each repository
31
+ 3. Repository imports run after GitLab import completes
32
+ 4. Each repository import generates TechnologyArtifact resources
33
+ MD
34
+
35
+ icon "download"
36
+ layer "other"
37
+
38
+ # Handler selection
39
+ annotation "import/handler",
40
+ description: "Handler class name to execute this import",
41
+ title: "Handler", enum: %w[
42
+ gitlab github repository
43
+ rest-api rest-api-index
44
+ jira-discover jira-metrics
45
+ ]
46
+
47
+ # Output configuration
48
+ annotation "import/outputPath",
49
+ description: "Output file path relative to resources root (e.g., 'imports/generated/gitlab.yaml')",
50
+ title: "Output Path"
51
+
52
+ # Control flags
53
+ annotation "import/enabled",
54
+ description: "Whether this import is enabled",
55
+ title: "Enabled",
56
+ enum: %w[true false]
57
+
58
+ annotation "import/priority",
59
+ description: "Execution priority (lower runs first among ready imports)",
60
+ title: "Priority",
61
+ type: Integer
62
+
63
+ annotation "import/cacheTime",
64
+ description: "Cache duration (e.g., '30m', '1h', '24h', '7d'). Set to 'never' to always run.",
65
+ title: "Cache Time"
66
+
67
+ # Handler-specific configuration (pattern annotation)
68
+ annotation "import/config/*",
69
+ description: "Handler-specific configuration values",
70
+ sidebar: false
71
+
72
+ # Generated resources relations - auto-tracked by handlers
73
+ # Dependencies are derived from the inverse of generates - if A generates B, B depends on A
74
+ relation :generates, :technologyArtifacts, :TechnologyArtifact
75
+ relation :generates, :applicationInterfaces, :ApplicationInterface
76
+ relation :generates, :dataObjects, :DataObject
77
+ relation :generates, :imports, :Import
78
+ relation :generates, :businessActors, :BusinessActor
79
+ end
@@ -72,8 +72,12 @@ class Archsight::Resources::TechnologyArtifact < Archsight::Resources::Base
72
72
  annotation "activity/status",
73
73
  description: "Repository activity status",
74
74
  title: "Activity Status",
75
- enum: %w[active abandoned bot-only archived],
75
+ enum: %w[active abandoned bot-only archived inaccessible empty no-code],
76
76
  list: true
77
+ annotation "activity/reason",
78
+ description: "Reason for activity status (for non-standard statuses)",
79
+ title: "Status Reason",
80
+ sidebar: false
77
81
  annotation "activity/busFactor",
78
82
  description: "Bus factor assessment",
79
83
  title: "Bus Factor",
@@ -83,6 +87,10 @@ class Archsight::Resources::TechnologyArtifact < Archsight::Resources::Base
83
87
  description: "Date of first commit (repository creation)",
84
88
  title: "Created",
85
89
  type: Time
90
+ annotation "activity/lastHumanCommit",
91
+ description: "Date of last human commit (last activity)",
92
+ title: "Last Human Commit",
93
+ type: Time
86
94
  annotation "agentic/tools",
87
95
  description: "Agentic tools detected in repository",
88
96
  title: "Agentic Tools",
@@ -121,7 +129,20 @@ class Archsight::Resources::TechnologyArtifact < Archsight::Resources::Base
121
129
  annotation "repository/visibility",
122
130
  description: "Repository visibility classification",
123
131
  title: "Visibility",
124
- enum: %w[internal open-source public]
132
+ enum: %w[private internal open-source public]
133
+ annotation "repository/recentTags",
134
+ description: "Recent git tags (releases)",
135
+ title: "Recent Tags",
136
+ format: :tag_list,
137
+ sidebar: false
138
+ annotation "repository/accessible",
139
+ description: "Whether repository is accessible for cloning",
140
+ title: "Accessible",
141
+ enum: %w[true false]
142
+ annotation "repository/error",
143
+ description: "Error message if repository is not accessible",
144
+ title: "Access Error",
145
+ sidebar: false
125
146
  annotation "deployment/images",
126
147
  description: "OCI container image names published by this repository",
127
148
  title: "Container Images",
@@ -4,5 +4,5 @@
4
4
  # Do not edit manually.
5
5
 
6
6
  module Archsight
7
- VERSION = "0.1.2"
7
+ VERSION = "0.1.3"
8
8
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sinatra/base"
4
+ require "sinatra/extension"
5
+
6
+ module Archsight; end
7
+ module Archsight::Web; end
8
+ module Archsight::Web::API; end
9
+
10
+ # Documentation UI for the REST API
11
+ module Archsight::Web::API::Docs
12
+ extend Sinatra::Extension
13
+
14
+ get "/api/docs" do
15
+ erb :api_docs
16
+ end
17
+ end