dev_metrics 0.1.1 → 0.1.2
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/dev_metrics/client.rb +25 -33
- data/lib/dev_metrics/markdown.rb +5 -1
- data/lib/dev_metrics/query_builder.rb +44 -0
- data/lib/dev_metrics.rb +2 -2
- metadata +9 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 61eeda6933db54b48b7f7ca3941b035da3d04f9f9a8e6d414b8ef9db87a265ea
|
|
4
|
+
data.tar.gz: c2477155037f8f078dc7ffcc044c7cba1767915a0334434af365ddf967fcca06
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3ed77728ffae77e7e4ff2f84affc023902fabbd2c9cd2adce81cc3b40b88eb02d97f1c6ced8e7bf7323452234274b29229f3ea775618ab3324ecc3752f4130e3
|
|
7
|
+
data.tar.gz: b7d5c47d5d486014d03ab9829b4f325377aa0f5c07c7e64b5f1692d0d308333352f45ea9eaf3b89f6120a374be8ddfec7fb36d7054b037887ee1d8f9c74a5505
|
data/lib/dev_metrics/client.rb
CHANGED
|
@@ -3,6 +3,7 @@ require 'uri'
|
|
|
3
3
|
require 'date'
|
|
4
4
|
require 'json'
|
|
5
5
|
require 'time'
|
|
6
|
+
require_relative 'query_builder'
|
|
6
7
|
|
|
7
8
|
module DevMetrics
|
|
8
9
|
class Client
|
|
@@ -18,10 +19,17 @@ module DevMetrics
|
|
|
18
19
|
|
|
19
20
|
def process(period: Date.today)
|
|
20
21
|
uri = URI.parse(GITHUB_GRAPHQL_API)
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
builder = DevMetrics::QueryBuilder.new(@repo_name)
|
|
23
|
+
|
|
24
|
+
auth_request = build_request(uri, builder.access_auth_check)
|
|
25
|
+
auth_response = execute_request(uri, auth_request)
|
|
26
|
+
check_auth_errors!(auth_response)
|
|
27
|
+
|
|
28
|
+
pr_request = build_request(uri, builder.pull_requests_for(period))
|
|
29
|
+
pr_response = execute_request(uri, pr_request)
|
|
30
|
+
|
|
31
|
+
pr_data = parse_response(pr_response)
|
|
23
32
|
|
|
24
|
-
pr_data = parse_response(response)
|
|
25
33
|
filtered_prs = exclude_bots(pr_data)
|
|
26
34
|
correction_pr_count = count_correction_prs(filtered_prs)
|
|
27
35
|
|
|
@@ -31,11 +39,10 @@ module DevMetrics
|
|
|
31
39
|
|
|
32
40
|
private
|
|
33
41
|
|
|
34
|
-
def build_request(uri,
|
|
42
|
+
def build_request(uri, body)
|
|
35
43
|
request = Net::HTTP::Post.new(uri)
|
|
36
|
-
request[
|
|
37
|
-
request.body =
|
|
38
|
-
|
|
44
|
+
request['Authorization'] = "Bearer #{@access_token}"
|
|
45
|
+
request.body = body
|
|
39
46
|
request
|
|
40
47
|
end
|
|
41
48
|
|
|
@@ -44,12 +51,21 @@ module DevMetrics
|
|
|
44
51
|
Net::HTTP.start(uri.hostname, uri.port, options) { |http| http.request(request) }
|
|
45
52
|
end
|
|
46
53
|
|
|
54
|
+
def check_auth_errors!(response)
|
|
55
|
+
if response.code.to_i == 403 || response.body.include?('FORBIDDEN')
|
|
56
|
+
raise "Access denied: ensure the access token has permission to access #{@repo_name}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
47
60
|
def parse_response(response)
|
|
48
61
|
unless response.is_a?(Net::HTTPSuccess)
|
|
49
62
|
raise "Failed to fetch data: #{response.message} (#{response.code})"
|
|
50
63
|
end
|
|
51
64
|
|
|
52
|
-
JSON.parse(response.body)
|
|
65
|
+
data = JSON.parse(response.body)
|
|
66
|
+
raise "GraphQL error: #{data['errors']}" if data['errors']
|
|
67
|
+
|
|
68
|
+
data.dig('data', 'search', 'edges') || []
|
|
53
69
|
end
|
|
54
70
|
|
|
55
71
|
def exclude_bots(prs)
|
|
@@ -58,7 +74,7 @@ module DevMetrics
|
|
|
58
74
|
end
|
|
59
75
|
|
|
60
76
|
def count_correction_prs(prs)
|
|
61
|
-
prs.count { |pr| pr.dig('node', 'headRefName')&.match?(/^#{@fix_branch_names}/) }
|
|
77
|
+
prs.count { |pr| pr.dig('node', 'headRefName')&.match?(/^#{@fix_branch_names.join('|')}/) }
|
|
62
78
|
end
|
|
63
79
|
|
|
64
80
|
def calculate_lead_time(prs)
|
|
@@ -81,30 +97,6 @@ module DevMetrics
|
|
|
81
97
|
Time.at(remaining).utc.strftime("#{days}d %H:%M:%S")
|
|
82
98
|
end
|
|
83
99
|
|
|
84
|
-
def graphql_query(period)
|
|
85
|
-
query_string = <<-GRAPHQL
|
|
86
|
-
{
|
|
87
|
-
search(query: "repo:#{@repo_name} is:pr merged:#{period}", type: ISSUE, first: 100) {
|
|
88
|
-
edges {
|
|
89
|
-
node {
|
|
90
|
-
... on PullRequest {
|
|
91
|
-
url
|
|
92
|
-
title
|
|
93
|
-
author {
|
|
94
|
-
login
|
|
95
|
-
}
|
|
96
|
-
mergedAt
|
|
97
|
-
headRefName
|
|
98
|
-
publishedAt
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
GRAPHQL
|
|
105
|
-
{ "query" => query_string.strip }.to_json
|
|
106
|
-
end
|
|
107
|
-
|
|
108
100
|
def output_metrics(period, prs, correction_pr_count)
|
|
109
101
|
formatted_data = format_data(period, prs, correction_pr_count)
|
|
110
102
|
|
data/lib/dev_metrics/markdown.rb
CHANGED
|
@@ -8,12 +8,16 @@ module DevMetrics
|
|
|
8
8
|
def format_data(period, prs, correction_pr_count)
|
|
9
9
|
output = ""
|
|
10
10
|
output << "| #{period} | #{prs.count} | #{correction_pr_count} | "
|
|
11
|
-
output << "#{(
|
|
11
|
+
output << "#{correction_calc(correction_pr_count, prs)}% | "
|
|
12
12
|
output << "#{calculate_lead_time(prs)} | "
|
|
13
13
|
output << "[PRs for #{period}](https://github.com/#{@repo_name}/pulls?q=is%3Apr+merged%3A#{period}) |\n"
|
|
14
14
|
output
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def correction_calc(correction_pr_count, prs)
|
|
18
|
+
return "-" if prs.empty?
|
|
19
|
+
((correction_pr_count.to_f / prs.count) * 100).round(2)
|
|
20
|
+
end
|
|
17
21
|
def output_filename
|
|
18
22
|
"metrics_report.md"
|
|
19
23
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module DevMetrics
|
|
2
|
+
class QueryBuilder
|
|
3
|
+
|
|
4
|
+
def initialize(repo)
|
|
5
|
+
@repo = repo
|
|
6
|
+
end
|
|
7
|
+
def access_auth_check
|
|
8
|
+
to_body <<~GRAPHQL
|
|
9
|
+
{
|
|
10
|
+
repository(owner: "#{@repo.split('/')[0]}", name: "#{@repo.split('/')[1]}"){
|
|
11
|
+
id
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
GRAPHQL
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def pull_requests_for(period)
|
|
18
|
+
to_body <<~GRAPHQL
|
|
19
|
+
{
|
|
20
|
+
search(query: "repo:#{@repo} is:pr merged:#{period}", type: ISSUE, first: 100) {
|
|
21
|
+
edges {
|
|
22
|
+
node {
|
|
23
|
+
... on PullRequest {
|
|
24
|
+
url
|
|
25
|
+
title
|
|
26
|
+
author { login }
|
|
27
|
+
mergedAt
|
|
28
|
+
headRefName
|
|
29
|
+
publishedAt
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
GRAPHQL
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def to_body(query_string)
|
|
41
|
+
{ "query" => query_string.strip }.to_json
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/dev_metrics.rb
CHANGED
metadata
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dev_metrics
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- sean2121
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-04-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
|
-
description:
|
|
14
|
-
email:
|
|
13
|
+
description:
|
|
14
|
+
email:
|
|
15
15
|
executables: []
|
|
16
16
|
extensions: []
|
|
17
17
|
extra_rdoc_files: []
|
|
@@ -19,11 +19,12 @@ files:
|
|
|
19
19
|
- lib/dev_metrics.rb
|
|
20
20
|
- lib/dev_metrics/client.rb
|
|
21
21
|
- lib/dev_metrics/markdown.rb
|
|
22
|
-
|
|
22
|
+
- lib/dev_metrics/query_builder.rb
|
|
23
|
+
homepage:
|
|
23
24
|
licenses:
|
|
24
25
|
- MIT
|
|
25
26
|
metadata: {}
|
|
26
|
-
post_install_message:
|
|
27
|
+
post_install_message:
|
|
27
28
|
rdoc_options: []
|
|
28
29
|
require_paths:
|
|
29
30
|
- lib
|
|
@@ -39,7 +40,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
39
40
|
version: '0'
|
|
40
41
|
requirements: []
|
|
41
42
|
rubygems_version: 3.2.33
|
|
42
|
-
signing_key:
|
|
43
|
+
signing_key:
|
|
43
44
|
specification_version: 4
|
|
44
45
|
summary: A RubyGem for tracking and analyzing development metrics from various repositories.
|
|
45
46
|
test_files: []
|