codemonitor 0.3.1 → 0.3.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 +1 -1
- data/README.md +114 -3
- data/codemonitor.gemspec +1 -0
- data/engines/custom/extractor.rb +37 -0
- data/engines/github/extractor.rb +74 -0
- data/exe/codemonitor +5 -1
- data/lib/codemonitor/version.rb +1 -1
- data/providers/datadog.rb +2 -2
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54b2ce0b7c2997591225e5e7487433854b3fff767e3272b3d02210de337253cf
|
4
|
+
data.tar.gz: aa9a60e54480ec4602ec108f45b84323aa04aa46f3df622a4db2a303cb1e6ec3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47fb68d254802463f047d96ef409b111ee3f65c6e007a74122bb90151a4e4d457ed2b7b3c4e2bb6da0cc7da45284a933a43167714b39d7d6ebe291f68e8a1822
|
7
|
+
data.tar.gz: 2a466e51f3cd2e5936600680068af4bdb0ee717e9fcbfcc657394d08640f2b00799e2f82a3f183093bd6e1e8c0ee286c2948b3f5f777b5eb8e2e45fd464d4fcf
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,120 @@
|
|
1
|
-
# CodeMonitor
|
1
|
+
# 🖥️ CodeMonitor
|
2
2
|
|
3
3
|
A engine to collect multiple metrics from your repository and push them to a
|
4
4
|
time series provider.
|
5
5
|
|
6
6
|
|
7
|
-
#
|
7
|
+
# Engines
|
8
8
|
|
9
|
-
|
9
|
+
## Git
|
10
|
+
|
11
|
+
Collect multiple metrics from the a Git repository.
|
12
|
+
|
13
|
+
**Requirements / Setup**:
|
14
|
+
|
15
|
+
You need a `.git` folder present in the current folder:
|
16
|
+
|
17
|
+
**Options**:
|
18
|
+
|
19
|
+
`CODEMONITOR_GIT_FILES_THRESHOLD`: Don't emit metrics about number of files, from those that are above of this threshold. (Default: `0`)
|
20
|
+
|
21
|
+
## Eslint
|
22
|
+
|
23
|
+
Collect multiple metrics from the a project with [Eslint](https://eslint.org/) configured.
|
24
|
+
|
25
|
+
**Requirements / Setup**:
|
26
|
+
|
27
|
+
You need a `.eslintrc.js` and a `eslint.output.json` file present in the current folder.
|
28
|
+
|
29
|
+
You can generate the `eslint.output.json` file with this example command:
|
30
|
+
|
31
|
+
```
|
32
|
+
eslint -f json -o eslint.output.json
|
33
|
+
```
|
34
|
+
**Options**:
|
35
|
+
|
36
|
+
`CODEMONITOR_ESLINT_THRESHOLD`: Don't emit metrics about eslint rules that are above of this threshold. (Default: `10`)
|
37
|
+
|
38
|
+
|
39
|
+
## Npm
|
40
|
+
|
41
|
+
Collect multiple metrics from the a NodeJS.
|
42
|
+
|
43
|
+
**Requirements / Setup**:
|
44
|
+
|
45
|
+
You need a `package.json` file present in the current folder.
|
46
|
+
|
47
|
+
## Packwerk
|
48
|
+
|
49
|
+
Collect multiple metrics from the a Ruby project with [Packwerk](https://github.com/Shopify/packwerk) configured.
|
50
|
+
|
51
|
+
**Requirements / Setup**:
|
52
|
+
|
53
|
+
You need a `deprecated_references.yml` files present in the current project.
|
54
|
+
|
55
|
+
## Rubocop
|
56
|
+
|
57
|
+
Collect multiple metrics from the a Ruby project with [Rubocop](https://github.com/rubocop/rubocop) configured.
|
58
|
+
|
59
|
+
**Requirements / Setup**:
|
60
|
+
|
61
|
+
You need a `.rubocop.yml` and a `rubocop.output.json` file present in the current folder.
|
62
|
+
|
63
|
+
You can generate the `rubocop.output.json` file with this example command:
|
64
|
+
|
65
|
+
```
|
66
|
+
bundle exec srb tc --metrics-prefix 'codemetrics' --metrics-file sorbet.output.json
|
67
|
+
```
|
68
|
+
|
69
|
+
**Options**:
|
70
|
+
|
71
|
+
`CODEMONITOR_RUBOCOP_THRESHOLD`: Don't emit metrics about rubocop cops that are above of this threshold. (Default: `50`)
|
72
|
+
|
73
|
+
|
74
|
+
## Semgrep
|
75
|
+
|
76
|
+
Collect multiple metrics from the a with [Semgrep](https://semgrep.dev/) configured.
|
77
|
+
|
78
|
+
**Requirements / Setup**:
|
79
|
+
|
80
|
+
You need a `.semgrep.yml` and a `semgrep.output.json` file present in the current folder.
|
81
|
+
|
82
|
+
You can generate the `semgrep.output.json` file with this example command:
|
83
|
+
|
84
|
+
```
|
85
|
+
semgrep --json -o semgrep.output.json
|
86
|
+
```
|
87
|
+
|
88
|
+
**Options**:
|
89
|
+
|
90
|
+
`CODEMONITOR_SEMGREP_THRESHOLD`: Don't emit metrics about rubocop cops that are above of this threshold. (Default: `50`)
|
91
|
+
|
92
|
+
## Sorbet
|
93
|
+
|
94
|
+
Collect multiple metrics from the a with [Sorbet](https://sorbet.org/) configured.
|
95
|
+
|
96
|
+
**Requirements / Setup**:
|
97
|
+
|
98
|
+
You need a `sorbet.output.json` file present in the current folder.
|
99
|
+
|
100
|
+
You can generate the `sorbet.output.json` file with this example command:
|
101
|
+
|
102
|
+
```
|
103
|
+
bundle exec srb tc --metrics-prefix 'codemetrics' --metrics-file sorbet.output.json
|
104
|
+
```
|
105
|
+
|
106
|
+
# Providers
|
107
|
+
|
108
|
+
## Console
|
109
|
+
|
110
|
+
TODO
|
111
|
+
|
112
|
+
## Datadog
|
113
|
+
|
114
|
+
TODO
|
115
|
+
|
116
|
+
# Contribute
|
117
|
+
|
118
|
+
This project started as a side project, so I'm sure that is full
|
119
|
+
of mistakes and areas to be improve. If you think you can tweak the code to
|
120
|
+
make it better, I'll really appreciate a pull request. ;)
|
data/codemonitor.gemspec
CHANGED
@@ -37,6 +37,7 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.require_paths = ['lib']
|
38
38
|
|
39
39
|
spec.add_runtime_dependency 'dogapi', '~> 1.45'
|
40
|
+
spec.add_runtime_dependency 'octokit', '~> 4.0'
|
40
41
|
|
41
42
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
42
43
|
spec.add_development_dependency 'pry', '~> 0.13.1'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Engines
|
4
|
+
module Custom
|
5
|
+
class Extractor
|
6
|
+
def call(provider)
|
7
|
+
return unless requirements?
|
8
|
+
|
9
|
+
provider.emit(metrics)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def requirements?
|
15
|
+
custom_files.length.positive?
|
16
|
+
end
|
17
|
+
|
18
|
+
def custom_files
|
19
|
+
Dir.glob('./.codemonitor/*.rb')
|
20
|
+
end
|
21
|
+
|
22
|
+
def metrics
|
23
|
+
custom_files.map do |file|
|
24
|
+
values = begin
|
25
|
+
eval File.read(file)
|
26
|
+
rescue SyntaxError => e
|
27
|
+
raise "Unable to execute the custom codemonitor script `#{file}` file"
|
28
|
+
end
|
29
|
+
|
30
|
+
raise "Malformed return value from `#{file}` file. It must be a hash of metrics" unless values.is_a?(Hash)
|
31
|
+
|
32
|
+
values
|
33
|
+
end.reduce({}, :merge)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'octokit'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
Octokit.configure do |c|
|
7
|
+
c.auto_paginate = true
|
8
|
+
end
|
9
|
+
|
10
|
+
module Engines
|
11
|
+
module Github
|
12
|
+
class Extractor
|
13
|
+
METRICS = %i[
|
14
|
+
github_number_of_open_pull_requests
|
15
|
+
github_number_of_lead_time_in_days
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@access_token = ENV['GITHUB_TOKEN']
|
20
|
+
@repository = ENV['GITHUB_REPOSITORY']
|
21
|
+
@since_days = ENV['GITHUB_SINCE_DAYS'] || 30
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(provider)
|
25
|
+
return unless requirements?
|
26
|
+
|
27
|
+
metrics = METRICS.map do |metric|
|
28
|
+
[metric, send(metric)]
|
29
|
+
end.to_h
|
30
|
+
|
31
|
+
provider.emit(metrics)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :access_token, :repository, :since_days
|
37
|
+
|
38
|
+
def github
|
39
|
+
@github ||= Octokit::Client.new(access_token: access_token)
|
40
|
+
end
|
41
|
+
|
42
|
+
def requirements?
|
43
|
+
!access_token.nil? && !repository.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
def since
|
47
|
+
(Date.today - since_days).to_time.iso8601
|
48
|
+
end
|
49
|
+
|
50
|
+
def github_number_of_open_pull_requests
|
51
|
+
github.issues(repository, state: 'open').length
|
52
|
+
end
|
53
|
+
|
54
|
+
def github_number_of_lead_time_in_days
|
55
|
+
diffs = github
|
56
|
+
.issues(repository, since: since, state: 'closed')
|
57
|
+
.map do |issue|
|
58
|
+
next nil if issue[:pull_request][:merged_at].nil? || issue[:created_at].nil?
|
59
|
+
|
60
|
+
merged_at = Time.at(issue[:pull_request][:merged_at])
|
61
|
+
created_at = Time.at(issue[:created_at])
|
62
|
+
|
63
|
+
merged_at - created_at
|
64
|
+
end.reject do |diff|
|
65
|
+
diff.nil?
|
66
|
+
end
|
67
|
+
|
68
|
+
value = (diffs.reduce(:+) / diffs.size.to_f / (24 * 60 * 60))
|
69
|
+
|
70
|
+
value.round(2)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/exe/codemonitor
CHANGED
@@ -7,11 +7,13 @@ require_relative '../providers/datadog'
|
|
7
7
|
require_relative '../engines/eslint/extractor'
|
8
8
|
require_relative '../engines/debug/extractor'
|
9
9
|
require_relative '../engines/git/extractor'
|
10
|
+
require_relative '../engines/github/extractor'
|
10
11
|
require_relative '../engines/npm/extractor'
|
11
12
|
require_relative '../engines/packwerk/extractor'
|
12
13
|
require_relative '../engines/rubocop/extractor'
|
13
14
|
require_relative '../engines/semgrep/extractor'
|
14
15
|
require_relative '../engines/sorbet/extractor'
|
16
|
+
require_relative '../engines/custom/extractor'
|
15
17
|
|
16
18
|
PROVIDERS = {
|
17
19
|
console: Providers::Console,
|
@@ -22,11 +24,13 @@ EXTRACTORS = {
|
|
22
24
|
eslint: Engines::Eslint::Extractor,
|
23
25
|
debug: Engines::Debug::Extractor,
|
24
26
|
git: Engines::Git::Extractor,
|
27
|
+
github: Engines::Github::Extractor,
|
25
28
|
npm: Engines::Npm::Extractor,
|
26
29
|
packwerk: Engines::Packwerk::Extractor,
|
27
30
|
rubocop: Engines::Rubocop::Extractor,
|
28
31
|
semgrep: Engines::Semgrep::Extractor,
|
29
|
-
sorbet: Engines::Sorbet::Extractor
|
32
|
+
sorbet: Engines::Sorbet::Extractor,
|
33
|
+
custom: Engines::Custom::Extractor
|
30
34
|
}.freeze
|
31
35
|
|
32
36
|
config_provider = ENV['CODEMONITOR_PROVIDER'] || 'console'
|
data/lib/codemonitor/version.rb
CHANGED
data/providers/datadog.rb
CHANGED
@@ -17,7 +17,7 @@ module Providers
|
|
17
17
|
def send
|
18
18
|
datadog_client.batch_metrics do
|
19
19
|
pending.each do |metric, value|
|
20
|
-
metric = metric_prefix
|
20
|
+
metric = "#{metric_prefix}#{metric}"
|
21
21
|
puts "#{metric}: #{value}"
|
22
22
|
datadog_client.emit_point(metric, value, type: 'gauge')
|
23
23
|
end
|
@@ -26,6 +26,6 @@ module Providers
|
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
-
attr_reader :pending, :datadog_client
|
29
|
+
attr_reader :pending, :metric_prefix, :datadog_client
|
30
30
|
end
|
31
31
|
end
|
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.3.
|
4
|
+
version: 0.3.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: 2022-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dogapi
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.45'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: octokit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,9 +129,11 @@ files:
|
|
115
129
|
- bin/console
|
116
130
|
- bin/setup
|
117
131
|
- codemonitor.gemspec
|
132
|
+
- engines/custom/extractor.rb
|
118
133
|
- engines/debug/extractor.rb
|
119
134
|
- engines/eslint/extractor.rb
|
120
135
|
- engines/git/extractor.rb
|
136
|
+
- engines/github/extractor.rb
|
121
137
|
- engines/npm/extractor.rb
|
122
138
|
- engines/packwerk/extractor.rb
|
123
139
|
- engines/rubocop/extractor.rb
|