codemonitor 0.7.1 → 0.7.5
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/Gemfile.lock +14 -14
- data/README.md +460 -64
- data/engines/tsc/extractor.rb +183 -0
- data/exe/codemonitor +52 -12
- data/lib/codemonitor/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 62ece0078a173b6863e1cfe9e08ca70150d270abe25ec08aba06601f15ea2516
|
|
4
|
+
data.tar.gz: 40323f63b3fc1982bae1bb56c1f80ea16c4e11736d4d1280cfe4afc58c343fe4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1445c31e4ddfd0492a4bf1ebb8b939702c9c9bafbcadddc209a33ab90185b8593ee41d21904465329de751e926cb9f6888123dde679f56888cdf8c6c6fb3c73b
|
|
7
|
+
data.tar.gz: e37bc0f7965f010d686137975889e1d0d7292f2237ccd4c1c01f44ff16ee37789e0574e71d93fa5b69cab95636124ce5e6c4a09616ddaed64febb89863fddcd6
|
data/Gemfile.lock
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
codemonitor (0.7.
|
|
4
|
+
codemonitor (0.7.5)
|
|
5
5
|
dogapi (~> 1.45)
|
|
6
6
|
octokit (~> 9.0)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
10
10
|
specs:
|
|
11
|
-
addressable (2.8.
|
|
12
|
-
public_suffix (>= 2.0.2, <
|
|
11
|
+
addressable (2.8.8)
|
|
12
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
13
13
|
ast (2.4.2)
|
|
14
14
|
coderay (1.1.3)
|
|
15
15
|
diff-lcs (1.3)
|
|
16
16
|
dogapi (1.45.0)
|
|
17
17
|
multi_json
|
|
18
|
-
faraday (2.
|
|
18
|
+
faraday (2.14.0)
|
|
19
19
|
faraday-net_http (>= 2.0, < 3.5)
|
|
20
20
|
json
|
|
21
21
|
logger
|
|
22
|
-
faraday-net_http (3.4.
|
|
23
|
-
net-http (
|
|
24
|
-
json (2.
|
|
22
|
+
faraday-net_http (3.4.2)
|
|
23
|
+
net-http (~> 0.5)
|
|
24
|
+
json (2.18.1)
|
|
25
25
|
logger (1.7.0)
|
|
26
26
|
method_source (1.0.0)
|
|
27
|
-
multi_json (1.
|
|
28
|
-
net-http (0.
|
|
29
|
-
uri
|
|
27
|
+
multi_json (1.19.1)
|
|
28
|
+
net-http (0.9.1)
|
|
29
|
+
uri (>= 0.11.1)
|
|
30
30
|
octokit (9.2.0)
|
|
31
31
|
faraday (>= 1, < 3)
|
|
32
32
|
sawyer (~> 0.9)
|
|
@@ -36,7 +36,7 @@ GEM
|
|
|
36
36
|
pry (0.13.1)
|
|
37
37
|
coderay (~> 1.1)
|
|
38
38
|
method_source (~> 1.0)
|
|
39
|
-
public_suffix (
|
|
39
|
+
public_suffix (7.0.2)
|
|
40
40
|
rainbow (3.0.0)
|
|
41
41
|
rake (13.0.3)
|
|
42
42
|
regexp_parser (2.1.1)
|
|
@@ -66,11 +66,11 @@ GEM
|
|
|
66
66
|
rubocop-ast (1.5.0)
|
|
67
67
|
parser (>= 3.0.1.1)
|
|
68
68
|
ruby-progressbar (1.11.0)
|
|
69
|
-
sawyer (0.9.
|
|
69
|
+
sawyer (0.9.3)
|
|
70
70
|
addressable (>= 2.3.5)
|
|
71
71
|
faraday (>= 0.17.3, < 3)
|
|
72
72
|
unicode-display_width (1.7.0)
|
|
73
|
-
uri (1.
|
|
73
|
+
uri (1.1.1)
|
|
74
74
|
|
|
75
75
|
PLATFORMS
|
|
76
76
|
ruby
|
|
@@ -84,4 +84,4 @@ DEPENDENCIES
|
|
|
84
84
|
rubocop (~> 0.80)
|
|
85
85
|
|
|
86
86
|
BUNDLED WITH
|
|
87
|
-
2.
|
|
87
|
+
2.7.2
|
data/README.md
CHANGED
|
@@ -1,145 +1,452 @@
|
|
|
1
1
|
# 🖥️ CodeMonitor
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
time series provider.
|
|
3
|
+
**CodeMonitor** is a powerful Ruby gem that collects code quality metrics, dependency information, test coverage, and other important statistics from your repository. It aggregates data from multiple analysis tools (linters, type checkers, test frameworks, etc.) and sends them to time series databases or monitoring providers like Datadog for tracking trends over time.
|
|
5
4
|
|
|
5
|
+
## 📊 What Does It Do?
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
CodeMonitor acts as a centralized metrics collection hub for your codebase. It:
|
|
8
|
+
|
|
9
|
+
- **Collects metrics** from various development tools and analysis extractors
|
|
10
|
+
- **Aggregates data** from linters (ESLint, Rubocop, Semgrep), type checkers (Sorbet), test coverage tools (Jest, SimpleCov), dependency analyzers (npm, Knip, Packwerk), and more
|
|
11
|
+
- **Normalizes metrics** into a consistent format
|
|
12
|
+
- **Pushes data** to monitoring providers (Datadog, Console output)
|
|
13
|
+
- **Tracks trends** over time to help you monitor code quality, technical debt, and project health
|
|
14
|
+
|
|
15
|
+
## 🚀 Installation
|
|
16
|
+
|
|
17
|
+
Add this line to your application's Gemfile:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
gem 'codemonitor'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
And then execute:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bundle install
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or install it yourself as:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
gem install codemonitor
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 💻 Usage
|
|
36
|
+
|
|
37
|
+
### Basic Usage
|
|
38
|
+
|
|
39
|
+
Run CodeMonitor in your project directory:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
codemonitor
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
By default, it will:
|
|
46
|
+
1. Auto-detect which extractors are available (based on configuration files)
|
|
47
|
+
2. Collect metrics from all detected extractors
|
|
48
|
+
3. Output results to the console
|
|
49
|
+
|
|
50
|
+
### Configuration
|
|
51
|
+
|
|
52
|
+
Configure CodeMonitor using environment variables:
|
|
53
|
+
|
|
54
|
+
- **`CODEMONITOR_PROVIDER`**: Choose where to send metrics (`console` or `datadog`). Default: `console`
|
|
55
|
+
- **`CODEMONITOR_EXTRACTORS`**: Comma-separated list of specific extractors to run (e.g., `git,eslint,npm`). If not set, all available extractors run.
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Send metrics to Datadog
|
|
61
|
+
CODEMONITOR_PROVIDER=datadog DATADOG_API_KEY=your_key codemonitor
|
|
62
|
+
|
|
63
|
+
# Run only specific extractors
|
|
64
|
+
CODEMONITOR_EXTRACTORS=git,npm,eslint codemonitor
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
# Extractors
|
|
68
|
+
|
|
69
|
+
Extractors are the data collectors that extract metrics from various tools and sources. Each extractor automatically activates when its requirements are met.
|
|
8
70
|
|
|
9
71
|
## Git
|
|
10
72
|
|
|
11
|
-
|
|
73
|
+
Collects repository statistics including commits, branches, tags, contributors, and file metrics.
|
|
12
74
|
|
|
13
|
-
**Requirements
|
|
75
|
+
**Requirements**:
|
|
14
76
|
|
|
15
|
-
|
|
77
|
+
- A `.git` folder in the current directory
|
|
16
78
|
|
|
17
79
|
**Options**:
|
|
18
80
|
|
|
19
|
-
`CODEMONITOR_GIT_FILES_THRESHOLD`:
|
|
81
|
+
- `CODEMONITOR_GIT_FILES_THRESHOLD`: Filter out file extension metrics below this count (Default: `0`)
|
|
20
82
|
|
|
21
|
-
|
|
83
|
+
**Metrics**:
|
|
22
84
|
|
|
23
|
-
|
|
85
|
+
| Metric | Description |
|
|
86
|
+
|--------|-------------|
|
|
87
|
+
| `git_number_of_commits` | Total number of commits in the repository |
|
|
88
|
+
| `git_number_of_branches` | Total number of branches |
|
|
89
|
+
| `git_number_of_tags` | Total number of tags |
|
|
90
|
+
| `git_number_of_contributors` | Total number of unique contributors |
|
|
91
|
+
| `git_number_of_files` | Total number of tracked files |
|
|
92
|
+
| `git_number_of_ignores_files` | Number of ignored files |
|
|
93
|
+
| `git_number_of_lines` | Total lines of code across all files |
|
|
94
|
+
| `git_file_extensions_*` | File count per extension (e.g., `git_file_extensions_rb`, `git_file_extensions_js`) |
|
|
24
95
|
|
|
25
|
-
|
|
96
|
+
## ESLint
|
|
26
97
|
|
|
27
|
-
|
|
98
|
+
Collects JavaScript/TypeScript linting metrics including violations by severity and rule.
|
|
28
99
|
|
|
29
|
-
|
|
100
|
+
**Requirements**:
|
|
30
101
|
|
|
31
|
-
|
|
102
|
+
- `eslint.output.json` file in the current directory
|
|
103
|
+
|
|
104
|
+
Generate the required file:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
32
107
|
eslint -f json -o eslint.output.json
|
|
33
108
|
```
|
|
109
|
+
|
|
34
110
|
**Options**:
|
|
35
111
|
|
|
36
|
-
`CODEMONITOR_ESLINT_THRESHOLD`:
|
|
112
|
+
- `CODEMONITOR_ESLINT_THRESHOLD`: Only report rules with violations >= this threshold (Default: `10`)
|
|
113
|
+
|
|
114
|
+
**Metrics**:
|
|
115
|
+
|
|
116
|
+
| Metric | Description |
|
|
117
|
+
|--------|-------------|
|
|
118
|
+
| `eslint_number_of_offended_files` | Number of files with ESLint violations |
|
|
119
|
+
| `eslint_number_of_offenses` | Total number of ESLint violations |
|
|
120
|
+
| `eslint_number_of_correctable` | Number of auto-fixable violations |
|
|
121
|
+
| `eslint_severity_warning` | Number of warnings |
|
|
122
|
+
| `eslint_severity_error` | Number of errors |
|
|
123
|
+
| `eslint_rule_*` | Violation count per rule (e.g., `eslint_rule_no_console`) |
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
## npm
|
|
37
127
|
|
|
128
|
+
Collects Node.js dependency information including counts, computed dependencies, and vulnerability data from npm audit.
|
|
38
129
|
|
|
39
|
-
|
|
130
|
+
**Requirements**:
|
|
40
131
|
|
|
41
|
-
|
|
132
|
+
- `package.json` file in the current directory
|
|
133
|
+
- `package-lock.json` file in the current directory
|
|
42
134
|
|
|
43
|
-
**
|
|
135
|
+
**Metrics**:
|
|
44
136
|
|
|
45
|
-
|
|
137
|
+
| Metric | Description |
|
|
138
|
+
|--------|-------------|
|
|
139
|
+
| `npm_number_of_prod_dependencies` | Number of production dependencies |
|
|
140
|
+
| `npm_number_of_dev_dependencies` | Number of development dependencies |
|
|
141
|
+
| `npm_number_of_scripts` | Number of npm scripts defined |
|
|
142
|
+
| `npm_number_of_computed_prod_dependencies` | Total production dependencies (including transitive) |
|
|
143
|
+
| `npm_number_of_computed_dev_dependencies` | Total dev dependencies (including transitive) |
|
|
144
|
+
| `npm_number_of_computed_optional_dependencies` | Total optional dependencies |
|
|
145
|
+
| `npm_number_of_computed_peer_dependencies` | Total peer dependencies |
|
|
146
|
+
| `npm_number_of_computed_peer_optional_dependencies` | Total optional peer dependencies |
|
|
147
|
+
| `npm_number_of_computed_total_dependencies` | Grand total of all dependencies |
|
|
148
|
+
| `npm_number_of_vulnerable_dependencies_info` | Vulnerabilities: info severity |
|
|
149
|
+
| `npm_number_of_vulnerable_dependencies_low` | Vulnerabilities: low severity |
|
|
150
|
+
| `npm_number_of_vulnerable_dependencies_moderate` | Vulnerabilities: moderate severity |
|
|
151
|
+
| `npm_number_of_vulnerable_dependencies_high` | Vulnerabilities: high severity |
|
|
152
|
+
| `npm_number_of_vulnerable_dependencies_critical` | Vulnerabilities: critical severity |
|
|
153
|
+
| `npm_number_of_vulnerable_dependencies_total` | Total number of vulnerabilities |
|
|
46
154
|
|
|
47
155
|
## Packwerk
|
|
48
156
|
|
|
49
|
-
|
|
157
|
+
Collects metrics from Shopify's [Packwerk](https://github.com/Shopify/packwerk) package system for Ruby, tracking dependency and privacy violations.
|
|
50
158
|
|
|
51
|
-
**Requirements
|
|
159
|
+
**Requirements**:
|
|
52
160
|
|
|
53
|
-
|
|
161
|
+
- `package_todo.yml` files present in the project (in any subdirectory)
|
|
162
|
+
|
|
163
|
+
**Metrics**:
|
|
164
|
+
|
|
165
|
+
| Metric | Description |
|
|
166
|
+
|--------|-------------|
|
|
167
|
+
| `packwerk_number_of_dependency_violations` | Number of package dependency violations |
|
|
168
|
+
| `packwerk_number_of_privacy_violations` | Number of package privacy violations |
|
|
54
169
|
|
|
55
170
|
## Rubocop
|
|
56
171
|
|
|
57
|
-
|
|
172
|
+
Collects Ruby linting metrics from [Rubocop](https://github.com/rubocop/rubocop), including violations by severity and cop.
|
|
58
173
|
|
|
59
|
-
**Requirements
|
|
174
|
+
**Requirements**:
|
|
60
175
|
|
|
61
|
-
|
|
176
|
+
- `rubocop.output.json` file in the current directory
|
|
62
177
|
|
|
63
|
-
|
|
178
|
+
Generate the required file:
|
|
64
179
|
|
|
65
|
-
```
|
|
66
|
-
bundle exec
|
|
180
|
+
```bash
|
|
181
|
+
bundle exec rubocop -f json -o rubocop.output.json
|
|
67
182
|
```
|
|
68
183
|
|
|
69
184
|
**Options**:
|
|
70
185
|
|
|
71
|
-
`CODEMONITOR_RUBOCOP_THRESHOLD`:
|
|
186
|
+
- `CODEMONITOR_RUBOCOP_THRESHOLD`: Only report cops with violations >= this threshold (Default: `50`)
|
|
187
|
+
|
|
188
|
+
**Metrics**:
|
|
189
|
+
|
|
190
|
+
| Metric | Description |
|
|
191
|
+
|--------|-------------|
|
|
192
|
+
| `rubocop_number_of_offenses` | Total number of Rubocop violations |
|
|
193
|
+
| `rubocop_number_of_correctable` | Number of auto-correctable violations |
|
|
194
|
+
| `rubocop_severity_*` | Violations by severity (e.g., `rubocop_severity_warning`) |
|
|
195
|
+
| `rubocop_cop_*` | Violations per cop (e.g., `rubocop_cop_style_frozen_string_literal_comment`) |
|
|
72
196
|
|
|
73
197
|
|
|
74
198
|
## Semgrep
|
|
75
199
|
|
|
76
|
-
|
|
200
|
+
Collects security and code quality findings from [Semgrep](https://semgrep.dev/).
|
|
77
201
|
|
|
78
|
-
**Requirements
|
|
202
|
+
**Requirements**:
|
|
79
203
|
|
|
80
|
-
|
|
204
|
+
- `semgrep.output.json` file in the current directory
|
|
81
205
|
|
|
82
|
-
|
|
206
|
+
Generate the required file:
|
|
83
207
|
|
|
84
|
-
```
|
|
208
|
+
```bash
|
|
85
209
|
semgrep --json -o semgrep.output.json
|
|
86
210
|
```
|
|
87
211
|
|
|
88
212
|
**Options**:
|
|
89
213
|
|
|
90
|
-
`CODEMONITOR_SEMGREP_THRESHOLD`:
|
|
214
|
+
- `CODEMONITOR_SEMGREP_THRESHOLD`: Only report check IDs with findings >= this threshold (Default: `50`)
|
|
215
|
+
|
|
216
|
+
**Metrics**:
|
|
217
|
+
|
|
218
|
+
| Metric | Description |
|
|
219
|
+
|--------|-------------|
|
|
220
|
+
| `semgrep_number_of_offenses` | Total number of Semgrep findings |
|
|
221
|
+
| `semgrep_number_of_errors` | Number of Semgrep errors during analysis |
|
|
222
|
+
| `semgrep_check_*` | Findings per check ID |
|
|
91
223
|
|
|
92
224
|
## Knip
|
|
93
225
|
|
|
94
|
-
|
|
226
|
+
Collects unused code metrics from [Knip](https://knip.dev/), identifying unused dependencies, exports, and types.
|
|
95
227
|
|
|
96
|
-
**Requirements
|
|
228
|
+
**Requirements**:
|
|
97
229
|
|
|
98
|
-
|
|
230
|
+
- `knip.output.json` file in the current directory
|
|
99
231
|
|
|
100
|
-
|
|
232
|
+
Generate the required file:
|
|
101
233
|
|
|
102
|
-
```
|
|
234
|
+
```bash
|
|
103
235
|
knip --reporter json > knip.output.json
|
|
104
236
|
```
|
|
105
237
|
|
|
238
|
+
**Metrics**:
|
|
239
|
+
|
|
240
|
+
| Metric | Description |
|
|
241
|
+
|--------|-------------|
|
|
242
|
+
| `knip_number_of_dependecies` | Unused dependencies |
|
|
243
|
+
| `knip_number_of_devDependencies` | Unused dev dependencies |
|
|
244
|
+
| `knip_number_of_optionalPeerDependencies` | Unused optional peer dependencies |
|
|
245
|
+
| `knip_number_of_unlisted` | Unlisted dependencies |
|
|
246
|
+
| `knip_number_of_binaries` | Unused binaries |
|
|
247
|
+
| `knip_number_of_unresolved` | Unresolved imports |
|
|
248
|
+
| `knip_number_of_exports` | Unused exports |
|
|
249
|
+
| `knip_number_of_types` | Unused types |
|
|
250
|
+
| `knip_number_of_enumMembers` | Unused enum members |
|
|
251
|
+
| `knip_number_of_duplicates` | Duplicate exports |
|
|
252
|
+
|
|
106
253
|
## Sorbet
|
|
107
254
|
|
|
108
|
-
|
|
255
|
+
Collects type coverage metrics from [Sorbet](https://sorbet.org/), Stripe's type checker for Ruby.
|
|
109
256
|
|
|
110
|
-
**Requirements
|
|
257
|
+
**Requirements**:
|
|
111
258
|
|
|
112
|
-
|
|
259
|
+
- `sorbet.output.json` file in the current directory
|
|
113
260
|
|
|
114
|
-
|
|
261
|
+
Generate the required file:
|
|
115
262
|
|
|
116
|
-
```
|
|
263
|
+
```bash
|
|
117
264
|
bundle exec srb tc --metrics-prefix 'codemetrics' --metrics-file sorbet.output.json
|
|
118
265
|
```
|
|
119
266
|
|
|
120
|
-
|
|
267
|
+
**Metrics**:
|
|
268
|
+
|
|
269
|
+
| Metric | Description |
|
|
270
|
+
|--------|-------------|
|
|
271
|
+
| `sorbet_number_of_sig_count` | Number of type signatures |
|
|
272
|
+
| `sorbet_number_of_input_classes_total` | Total number of classes |
|
|
273
|
+
| `sorbet_number_of_input_sends_total` | Total number of method calls |
|
|
274
|
+
| `sorbet_number_of_input_files` | Number of Ruby files analyzed |
|
|
275
|
+
| `sorbet_number_of_input_methods_total` | Total number of methods |
|
|
276
|
+
| `sorbet_number_of_input_modules_total` | Total number of modules |
|
|
277
|
+
| `sorbet_number_of_sigil_true` | Files with `typed: true` |
|
|
278
|
+
| `sorbet_number_of_sigil_false` | Files with `typed: false` |
|
|
279
|
+
| `sorbet_number_of_sigil_autogenerated` | Files with `typed: autogenerated` |
|
|
280
|
+
| `sorbet_number_of_sigil_strong` | Files with `typed: strong` |
|
|
281
|
+
| `sorbet_number_of_sigil_strict` | Files with `typed: strict` |
|
|
282
|
+
| `sorbet_number_of_sigil_ignore` | Files with `typed: ignore` |
|
|
283
|
+
|
|
284
|
+
## SCC (Sloc Cloc and Code)
|
|
285
|
+
|
|
286
|
+
Collects code statistics from [SCC](https://github.com/boyter/scc), including lines of code, complexity, and language breakdowns.
|
|
287
|
+
|
|
288
|
+
**Requirements**:
|
|
289
|
+
|
|
290
|
+
- `scc.output.json` file in the current directory
|
|
291
|
+
|
|
292
|
+
Generate the required file:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
scc -f json > scc.output.json
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Metrics**:
|
|
299
|
+
|
|
300
|
+
| Metric | Description |
|
|
301
|
+
|--------|-------------|
|
|
302
|
+
| `scc_total_bytes` | Total bytes across all files |
|
|
303
|
+
| `scc_total_lines` | Total lines across all files |
|
|
304
|
+
| `scc_total_code` | Total lines of code |
|
|
305
|
+
| `scc_total_comment` | Total comment lines |
|
|
306
|
+
| `scc_total_blank` | Total blank lines |
|
|
307
|
+
| `scc_total_complexity` | Total cyclomatic complexity |
|
|
308
|
+
| `scc_total_count` | Total number of files |
|
|
309
|
+
| `scc_total_weightedcomplexity` | Weighted complexity score |
|
|
310
|
+
| `scc_type_*_*` | Per-language metrics (e.g., `scc_type_ruby_code`, `scc_type_javascript_lines`) |
|
|
311
|
+
|
|
312
|
+
## Jest
|
|
313
|
+
|
|
314
|
+
Collects JavaScript/TypeScript test coverage metrics from Jest's JSON summary reporter.
|
|
315
|
+
|
|
316
|
+
**Requirements**:
|
|
317
|
+
|
|
318
|
+
- `jest_json_summary.output.json` file in the current directory
|
|
319
|
+
|
|
320
|
+
Configure Jest to generate this file using the `json-summary` reporter in your `jest.config.js`.
|
|
321
|
+
|
|
322
|
+
**Metrics**:
|
|
323
|
+
|
|
324
|
+
| Metric | Description |
|
|
325
|
+
|--------|-------------|
|
|
326
|
+
| `jest_json_summary_lines_total` | Total lines in test coverage |
|
|
327
|
+
| `jest_json_summary_lines_covered` | Covered lines |
|
|
328
|
+
| `jest_json_summary_lines_skipped` | Skipped lines |
|
|
329
|
+
| `jest_json_summary_lines_pct` | Line coverage percentage |
|
|
330
|
+
| `jest_json_summary_statements_*` | Statement coverage metrics |
|
|
331
|
+
| `jest_json_summary_functions_*` | Function coverage metrics |
|
|
332
|
+
| `jest_json_summary_branches_*` | Branch coverage metrics |
|
|
333
|
+
|
|
334
|
+
## SimpleCov
|
|
335
|
+
|
|
336
|
+
Collects Ruby test coverage metrics from [SimpleCov](https://github.com/simplecov-ruby/simplecov).
|
|
337
|
+
|
|
338
|
+
**Requirements**:
|
|
339
|
+
|
|
340
|
+
- `simplecov_json_coverage.output.json` file in the current directory
|
|
341
|
+
|
|
342
|
+
Configure SimpleCov to use the JSON formatter in your test setup.
|
|
121
343
|
|
|
122
|
-
|
|
344
|
+
**Metrics**:
|
|
123
345
|
|
|
124
|
-
|
|
346
|
+
| Metric | Description |
|
|
347
|
+
|--------|-------------|
|
|
348
|
+
| `simplecov_json_coverage_metrics_covered_percent` | Code coverage percentage |
|
|
349
|
+
| `simplecov_json_coverage_metrics_covered_strength` | Coverage strength score |
|
|
350
|
+
| `simplecov_json_coverage_metrics_covered_lines` | Number of covered lines |
|
|
351
|
+
| `simplecov_json_coverage_metrics_total_lines` | Total number of lines |
|
|
125
352
|
|
|
126
|
-
|
|
353
|
+
## TSC (TypeScript Compiler)
|
|
127
354
|
|
|
128
|
-
|
|
355
|
+
Collects TypeScript compiler diagnostics and performance metrics from `tsc --extendedDiagnostics` output.
|
|
129
356
|
|
|
357
|
+
**Requirements**:
|
|
358
|
+
|
|
359
|
+
- `tsc.output.txt` file in the current directory
|
|
360
|
+
|
|
361
|
+
Generate the required file:
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
pnpm tsc --extendedDiagnostics --incremental false > tsc.output.txt
|
|
130
365
|
```
|
|
131
|
-
|
|
366
|
+
|
|
367
|
+
Or using npm:
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
npm run tsc -- --extendedDiagnostics --incremental false > tsc.output.txt
|
|
132
371
|
```
|
|
133
372
|
|
|
373
|
+
**Metrics**:
|
|
374
|
+
|
|
375
|
+
| Metric | Description |
|
|
376
|
+
|--------|-------------|
|
|
377
|
+
| `tsc_files` | Total number of files analyzed |
|
|
378
|
+
| `tsc_lines_of_library` | Lines of library code |
|
|
379
|
+
| `tsc_lines_of_definitions` | Lines of type definitions |
|
|
380
|
+
| `tsc_lines_of_typescript` | Lines of TypeScript code |
|
|
381
|
+
| `tsc_lines_of_javascript` | Lines of JavaScript code |
|
|
382
|
+
| `tsc_lines_of_json` | Lines of JSON files |
|
|
383
|
+
| `tsc_lines_of_other` | Lines of other file types |
|
|
384
|
+
| `tsc_identifiers` | Total number of identifiers |
|
|
385
|
+
| `tsc_symbols` | Total number of symbols |
|
|
386
|
+
| `tsc_types` | Total number of types |
|
|
387
|
+
| `tsc_instantiations` | Total number of type instantiations |
|
|
388
|
+
| `tsc_memory_used_kb` | Memory used by compiler (in kilobytes) |
|
|
389
|
+
| `tsc_assignability_cache_size` | Size of assignability cache |
|
|
390
|
+
| `tsc_identity_cache_size` | Size of identity cache |
|
|
391
|
+
| `tsc_subtype_cache_size` | Size of subtype cache |
|
|
392
|
+
| `tsc_strict_subtype_cache_size` | Size of strict subtype cache |
|
|
393
|
+
| `tsc_io_read_time_seconds` | Time spent reading files (seconds) |
|
|
394
|
+
| `tsc_parse_time_seconds` | Time spent parsing (seconds) |
|
|
395
|
+
| `tsc_resolve_module_time_seconds` | Time spent resolving modules (seconds) |
|
|
396
|
+
| `tsc_resolve_type_reference_time_seconds` | Time spent resolving type references (seconds) |
|
|
397
|
+
| `tsc_resolve_library_time_seconds` | Time spent resolving libraries (seconds) |
|
|
398
|
+
| `tsc_program_time_seconds` | Time spent on program construction (seconds) |
|
|
399
|
+
| `tsc_bind_time_seconds` | Time spent binding (seconds) |
|
|
400
|
+
| `tsc_check_time_seconds` | Time spent type checking (seconds) |
|
|
401
|
+
| `tsc_print_time_seconds` | Time spent printing (seconds) |
|
|
402
|
+
| `tsc_emit_time_seconds` | Time spent emitting output (seconds) |
|
|
403
|
+
| `tsc_total_time_seconds` | Total compilation time (seconds) |
|
|
404
|
+
|
|
405
|
+
## GitHub
|
|
406
|
+
|
|
407
|
+
Collects pull request metrics directly from GitHub, including open PRs and lead time.
|
|
408
|
+
|
|
409
|
+
**Requirements**:
|
|
410
|
+
|
|
411
|
+
- `GITHUB_TOKEN` environment variable with a GitHub personal access token
|
|
412
|
+
- `GITHUB_REPOSITORY` environment variable (format: `owner/repo`)
|
|
413
|
+
|
|
414
|
+
**Options**:
|
|
415
|
+
|
|
416
|
+
- `GITHUB_SINCE_DAYS`: Number of days to look back for lead time calculation (Default: `30`)
|
|
417
|
+
|
|
418
|
+
Example:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
GITHUB_TOKEN=ghp_xxx GITHUB_REPOSITORY=owner/repo codemonitor
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Metrics**:
|
|
425
|
+
|
|
426
|
+
| Metric | Description |
|
|
427
|
+
|--------|-------------|
|
|
428
|
+
| `github_number_of_open_pull_requests` | Number of open pull requests |
|
|
429
|
+
| `github_number_of_lead_time_in_days` | Average lead time for merged PRs (in days) |
|
|
430
|
+
|
|
134
431
|
# Providers
|
|
135
432
|
|
|
433
|
+
Providers determine where the collected metrics are sent. CodeMonitor supports multiple output destinations.
|
|
434
|
+
|
|
136
435
|
## Console
|
|
137
436
|
|
|
138
|
-
|
|
437
|
+
Outputs all metrics to standard output in a simple text format.
|
|
139
438
|
|
|
140
439
|
**Usage**:
|
|
141
440
|
|
|
142
|
-
|
|
441
|
+
```bash
|
|
442
|
+
codemonitor # Console is the default provider
|
|
443
|
+
# OR
|
|
444
|
+
CODEMONITOR_PROVIDER=console codemonitor
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Output Format**:
|
|
448
|
+
|
|
449
|
+
The console provider prints metrics in the format `metric_name: value`. If metrics include tags (using the `#` delimiter), they are displayed as-is:
|
|
143
450
|
|
|
144
451
|
```
|
|
145
452
|
requests: 100
|
|
@@ -150,25 +457,114 @@ latency#backend,region:us-east-1,env:prod: 150
|
|
|
150
457
|
|
|
151
458
|
## Datadog
|
|
152
459
|
|
|
153
|
-
Sends metrics to Datadog using the Datadog API
|
|
460
|
+
Sends metrics to [Datadog](https://www.datadoghq.com/) using the Datadog API for monitoring and visualization over time.
|
|
461
|
+
|
|
462
|
+
**Usage**:
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
CODEMONITOR_PROVIDER=datadog DATADOG_API_KEY=your_api_key codemonitor
|
|
466
|
+
```
|
|
154
467
|
|
|
155
468
|
**Environment Variables**:
|
|
156
469
|
|
|
157
|
-
- `DATADOG_API_KEY` (required):
|
|
158
|
-
- `DATADOG_PREFIX` (optional):
|
|
470
|
+
- `DATADOG_API_KEY` (required): Your Datadog API key
|
|
471
|
+
- `DATADOG_PREFIX` (optional): Prefix added to all metric names (default: `'codemonitor.'`)
|
|
159
472
|
|
|
160
473
|
**Metric Tagging**:
|
|
161
474
|
|
|
162
|
-
The Datadog provider supports adding tags to metrics
|
|
475
|
+
The Datadog provider supports adding tags to metrics for better organization and filtering. Include tags in the metric name using the `#` delimiter:
|
|
476
|
+
|
|
477
|
+
- **Format**: `metric_name#tag1,tag2:value,tag3`
|
|
478
|
+
- **Example**: `requests#frontend,app:webserver` → sends metric `requests` with tags `['frontend', 'app:webserver']`
|
|
479
|
+
- Tags follow Datadog's standard format: simple tags (`tag`) or key-value pairs (`key:value`)
|
|
480
|
+
|
|
481
|
+
More about Datadog tagging: [Datadog Tagging Documentation](https://docs.datadoghq.com/getting_started/tagging/)
|
|
482
|
+
|
|
483
|
+
## 🔧 Advanced Usage
|
|
484
|
+
|
|
485
|
+
### Running Specific Extractors
|
|
486
|
+
|
|
487
|
+
To run only specific extractors, use the `CODEMONITOR_EXTRACTORS` environment variable:
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
# Run only Git and ESLint extractors
|
|
491
|
+
CODEMONITOR_EXTRACTORS=git,eslint codemonitor
|
|
492
|
+
|
|
493
|
+
# Run npm and Rubocop with Datadog output
|
|
494
|
+
CODEMONITOR_PROVIDER=datadog DATADOG_API_KEY=xxx CODEMONITOR_EXTRACTORS=npm,rubocop codemonitor
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Interactive Mode
|
|
498
|
+
|
|
499
|
+
CodeMonitor can accept metrics directly from standard input using the `--interactive` flag. This allows you to send custom metrics without needing to configure extractors:
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
codemonitor --interactive <<EOF
|
|
503
|
+
{
|
|
504
|
+
metric_name: 100,
|
|
505
|
+
another_metric: 200,
|
|
506
|
+
"tagged_metric#tag1,tag2:value": 300
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
EOF
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
The interactive mode reads from stdin until it encounters two consecutive empty lines. The input must be a valid Ruby hash. This is useful for:
|
|
514
|
+
- Sending ad-hoc metrics
|
|
515
|
+
- Integrating with scripts that generate metrics dynamically
|
|
516
|
+
- Testing providers without setting up extractors
|
|
517
|
+
|
|
518
|
+
## Environment Variables
|
|
519
|
+
|
|
520
|
+
- `CODEMONITOR_PROVIDER`: Provider to use (default: `console`, options: `console`, `datadog`)
|
|
521
|
+
- `CODEMONITOR_EXTRACTORS`: Comma-separated list of extractors to run (default: all extractors)
|
|
522
|
+
|
|
523
|
+
For provider-specific configuration, see the [Providers](#providers) section below.
|
|
524
|
+
|
|
525
|
+
### CI/CD Integration
|
|
526
|
+
|
|
527
|
+
CodeMonitor is designed to run in CI/CD pipelines. Here's an example GitHub Actions workflow:
|
|
528
|
+
|
|
529
|
+
```yaml
|
|
530
|
+
name: Code Metrics
|
|
531
|
+
on: [push]
|
|
532
|
+
|
|
533
|
+
jobs:
|
|
534
|
+
metrics:
|
|
535
|
+
runs-on: ubuntu-latest
|
|
536
|
+
steps:
|
|
537
|
+
- uses: actions/checkout@v2
|
|
538
|
+
|
|
539
|
+
# Generate output files for various tools
|
|
540
|
+
- name: Run ESLint
|
|
541
|
+
run: eslint -f json -o eslint.output.json || true
|
|
542
|
+
|
|
543
|
+
- name: Run Rubocop
|
|
544
|
+
run: bundle exec rubocop -f json -o rubocop.output.json || true
|
|
545
|
+
|
|
546
|
+
# Collect and send metrics
|
|
547
|
+
- name: Run CodeMonitor
|
|
548
|
+
env:
|
|
549
|
+
CODEMONITOR_PROVIDER: datadog
|
|
550
|
+
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
|
|
551
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
552
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
553
|
+
run: codemonitor
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Best Practices
|
|
557
|
+
|
|
558
|
+
1. **Generate tool outputs before running CodeMonitor**: Most extractors require JSON output files from their respective tools
|
|
559
|
+
2. **Use thresholds wisely**: Adjust threshold values to focus on significant metrics and reduce noise
|
|
560
|
+
3. **Track trends over time**: Send metrics to Datadog or similar to visualize trends and set up alerts
|
|
561
|
+
4. **Run in CI/CD**: Automate metric collection on every commit or pull request
|
|
562
|
+
5. **Combine multiple extractors**: Use Git + linters + test coverage for a comprehensive health overview
|
|
163
563
|
|
|
164
|
-
|
|
165
|
-
- Example: `requests#frontend,app:webserver` → sends metric `requests` with tags `['frontend', 'app:webserver']`
|
|
166
|
-
- Tags follow Datadog's standard format where tags can be simple (`tag`) or key-value pairs (`key:value`)
|
|
564
|
+
## 🤝 Contribute
|
|
167
565
|
|
|
168
|
-
|
|
566
|
+
This project started as a side project, so there's always room for improvement! If you have ideas for new extractors, better metrics, or code improvements, pull requests are very welcome. 😊
|
|
169
567
|
|
|
170
|
-
|
|
568
|
+
## 📝 License
|
|
171
569
|
|
|
172
|
-
This project
|
|
173
|
-
of mistakes and areas to be improve. If you think you can tweak the code to
|
|
174
|
-
make it better, I'll really appreciate a pull request. ;)
|
|
570
|
+
This project is available under the MIT License. See the LICENSE file for details.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Engines
|
|
4
|
+
module Tsc
|
|
5
|
+
class Extractor
|
|
6
|
+
METRICS = %i[
|
|
7
|
+
tsc_files
|
|
8
|
+
tsc_lines_of_library
|
|
9
|
+
tsc_lines_of_definitions
|
|
10
|
+
tsc_lines_of_typescript
|
|
11
|
+
tsc_lines_of_javascript
|
|
12
|
+
tsc_lines_of_json
|
|
13
|
+
tsc_lines_of_other
|
|
14
|
+
tsc_identifiers
|
|
15
|
+
tsc_symbols
|
|
16
|
+
tsc_types
|
|
17
|
+
tsc_instantiations
|
|
18
|
+
tsc_memory_used_kb
|
|
19
|
+
tsc_assignability_cache_size
|
|
20
|
+
tsc_identity_cache_size
|
|
21
|
+
tsc_subtype_cache_size
|
|
22
|
+
tsc_strict_subtype_cache_size
|
|
23
|
+
tsc_io_read_time_seconds
|
|
24
|
+
tsc_parse_time_seconds
|
|
25
|
+
tsc_resolve_module_time_seconds
|
|
26
|
+
tsc_resolve_type_reference_time_seconds
|
|
27
|
+
tsc_resolve_library_time_seconds
|
|
28
|
+
tsc_program_time_seconds
|
|
29
|
+
tsc_bind_time_seconds
|
|
30
|
+
tsc_check_time_seconds
|
|
31
|
+
tsc_print_time_seconds
|
|
32
|
+
tsc_emit_time_seconds
|
|
33
|
+
tsc_total_time_seconds
|
|
34
|
+
].freeze
|
|
35
|
+
|
|
36
|
+
def call(provider)
|
|
37
|
+
metrics = METRICS.map do |metric|
|
|
38
|
+
[metric, send(metric)]
|
|
39
|
+
end.to_h
|
|
40
|
+
|
|
41
|
+
provider.emit(metrics)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def requirements?
|
|
45
|
+
File.exist?('tsc.output.txt')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def tsc_output
|
|
51
|
+
@tsc_output ||= File.read('tsc.output.txt')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def extract_integer(pattern)
|
|
55
|
+
match = tsc_output.match(pattern)
|
|
56
|
+
return 0 if match.nil?
|
|
57
|
+
|
|
58
|
+
match[1].gsub(/\s+/, '').to_i
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def extract_time(pattern)
|
|
62
|
+
match = tsc_output.match(pattern)
|
|
63
|
+
return 0.0 if match.nil?
|
|
64
|
+
|
|
65
|
+
time_str = match[1]
|
|
66
|
+
# Convert time format like "0.63s" to 0.63
|
|
67
|
+
time_str.sub(/s$/, '').to_f
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def tsc_files
|
|
71
|
+
extract_integer(/^Files:\s+(\d+)/)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def tsc_lines_of_library
|
|
75
|
+
extract_integer(/^Lines of Library:\s+(\d+)/)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def tsc_lines_of_definitions
|
|
79
|
+
extract_integer(/^Lines of Definitions:\s+(\d+)/)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def tsc_lines_of_typescript
|
|
83
|
+
extract_integer(/^Lines of TypeScript:\s+(\d+)/)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def tsc_lines_of_javascript
|
|
87
|
+
extract_integer(/^Lines of JavaScript:\s+(\d+)/)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def tsc_lines_of_json
|
|
91
|
+
extract_integer(/^Lines of JSON:\s+(\d+)/)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def tsc_lines_of_other
|
|
95
|
+
extract_integer(/^Lines of Other:\s+(\d+)/)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def tsc_identifiers
|
|
99
|
+
extract_integer(/^Identifiers:\s+(\d+)/)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def tsc_symbols
|
|
103
|
+
extract_integer(/^Symbols:\s+(\d+)/)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def tsc_types
|
|
107
|
+
extract_integer(/^Types:\s+(\d+)/)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def tsc_instantiations
|
|
111
|
+
extract_integer(/^Instantiations:\s+(\d+)/)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def tsc_memory_used_kb
|
|
115
|
+
# Extract memory in KB (e.g., "6942037K" -> 6942037)
|
|
116
|
+
match = tsc_output.match(/^Memory used:\s+(\d+)K/)
|
|
117
|
+
return 0 if match.nil?
|
|
118
|
+
|
|
119
|
+
match[1].to_i
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def tsc_assignability_cache_size
|
|
123
|
+
extract_integer(/^Assignability cache size:\s+(\d+)/)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def tsc_identity_cache_size
|
|
127
|
+
extract_integer(/^Identity cache size:\s+(\d+)/)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def tsc_subtype_cache_size
|
|
131
|
+
extract_integer(/^Subtype cache size:\s+(\d+)/)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def tsc_strict_subtype_cache_size
|
|
135
|
+
extract_integer(/^Strict subtype cache size:\s+(\d+)/)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def tsc_io_read_time_seconds
|
|
139
|
+
extract_time(/^I\/O Read time:\s+([\d.]+s)/)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def tsc_parse_time_seconds
|
|
143
|
+
extract_time(/^Parse time:\s+([\d.]+s)/)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def tsc_resolve_module_time_seconds
|
|
147
|
+
extract_time(/^ResolveModule time:\s+([\d.]+s)/)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def tsc_resolve_type_reference_time_seconds
|
|
151
|
+
extract_time(/^ResolveTypeReference time:\s+([\d.]+s)/)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def tsc_resolve_library_time_seconds
|
|
155
|
+
extract_time(/^ResolveLibrary time:\s+([\d.]+s)/)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def tsc_program_time_seconds
|
|
159
|
+
extract_time(/^Program time:\s+([\d.]+s)/)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def tsc_bind_time_seconds
|
|
163
|
+
extract_time(/^Bind time:\s+([\d.]+s)/)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def tsc_check_time_seconds
|
|
167
|
+
extract_time(/^Check time:\s+([\d.]+s)/)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def tsc_print_time_seconds
|
|
171
|
+
extract_time(/^printTime time:\s+([\d.]+s)/)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def tsc_emit_time_seconds
|
|
175
|
+
extract_time(/^Emit time:\s+([\d.]+s)/)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def tsc_total_time_seconds
|
|
179
|
+
extract_time(/^Total time:\s+([\d.]+s)/)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
data/exe/codemonitor
CHANGED
|
@@ -18,6 +18,7 @@ require_relative '../engines/scc/extractor'
|
|
|
18
18
|
require_relative '../engines/semgrep/extractor'
|
|
19
19
|
require_relative '../engines/simplecov-json-coverage/extractor'
|
|
20
20
|
require_relative '../engines/sorbet/extractor'
|
|
21
|
+
require_relative '../engines/tsc/extractor'
|
|
21
22
|
|
|
22
23
|
PROVIDERS = {
|
|
23
24
|
console: Providers::Console,
|
|
@@ -38,30 +39,69 @@ EXTRACTORS = {
|
|
|
38
39
|
scc: Engines::Scc::Extractor,
|
|
39
40
|
semgrep: Engines::Semgrep::Extractor,
|
|
40
41
|
simplecov_json_coverage: Engines::SimpleCovJsonCoverage::Extractor,
|
|
41
|
-
sorbet: Engines::Sorbet::Extractor
|
|
42
|
+
sorbet: Engines::Sorbet::Extractor,
|
|
43
|
+
tsc: Engines::Tsc::Extractor
|
|
42
44
|
}.freeze
|
|
43
45
|
|
|
46
|
+
# Parse command-line arguments
|
|
47
|
+
interactive_mode = ARGV.include?('--interactive')
|
|
48
|
+
|
|
44
49
|
config_provider = ENV['CODEMONITOR_PROVIDER'] || 'console'
|
|
45
50
|
config_extractors = ENV['CODEMONITOR_EXTRACTORS']
|
|
46
51
|
|
|
47
52
|
provider = PROVIDERS[config_provider.to_sym].new
|
|
48
|
-
extractors = if config_extractors
|
|
49
|
-
EXTRACTORS.slice(*config_extractors.split(',').map(&:to_sym)).values
|
|
50
|
-
else
|
|
51
|
-
EXTRACTORS.values
|
|
52
|
-
end
|
|
53
53
|
|
|
54
54
|
puts '# process start'
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
if interactive_mode
|
|
57
|
+
# Read from stdin until two consecutive empty lines
|
|
58
|
+
lines = []
|
|
59
|
+
empty_line_count = 0
|
|
60
|
+
|
|
61
|
+
while empty_line_count < 2
|
|
62
|
+
line = $stdin.gets
|
|
63
|
+
break unless line
|
|
64
|
+
|
|
65
|
+
line = line.chomp
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
if line.empty?
|
|
68
|
+
empty_line_count += 1
|
|
69
|
+
else
|
|
70
|
+
empty_line_count = 0
|
|
71
|
+
lines << line
|
|
72
|
+
end
|
|
63
73
|
end
|
|
64
74
|
|
|
75
|
+
# Join the lines and evaluate as a Ruby hash
|
|
76
|
+
input_str = lines.join("\n")
|
|
77
|
+
|
|
78
|
+
begin
|
|
79
|
+
metrics = eval(input_str)
|
|
80
|
+
raise "Input must be a Hash" unless metrics.is_a?(Hash)
|
|
81
|
+
|
|
82
|
+
provider.emit(metrics)
|
|
83
|
+
rescue SyntaxError, StandardError => e
|
|
84
|
+
puts "Error parsing input: #{e.message}"
|
|
85
|
+
exit 1
|
|
86
|
+
end
|
|
87
|
+
else
|
|
88
|
+
# Original behavior: run extractors
|
|
89
|
+
extractors = if config_extractors
|
|
90
|
+
EXTRACTORS.slice(*config_extractors.split(',').map(&:to_sym)).values
|
|
91
|
+
else
|
|
92
|
+
EXTRACTORS.values
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Run all the extractors and collect the data
|
|
96
|
+
extractors
|
|
97
|
+
.map(&:new)
|
|
98
|
+
.map do |extractor|
|
|
99
|
+
raise "Requirements not fullfiled in #{extractor.class.name}" unless extractor.requirements?
|
|
100
|
+
|
|
101
|
+
extractor.call(provider)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
65
105
|
# Send all the data to the provider
|
|
66
106
|
provider.send
|
|
67
107
|
|
data/lib/codemonitor/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: codemonitor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ferran Basora
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-02-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: dogapi
|
|
@@ -144,6 +144,7 @@ files:
|
|
|
144
144
|
- engines/semgrep/extractor.rb
|
|
145
145
|
- engines/simplecov-json-coverage/extractor.rb
|
|
146
146
|
- engines/sorbet/extractor.rb
|
|
147
|
+
- engines/tsc/extractor.rb
|
|
147
148
|
- exe/codemonitor
|
|
148
149
|
- lib/codemonitor/version.rb
|
|
149
150
|
- lib/shell.rb
|