time_to_first_comment 0.1.0
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 +7 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.rubocop.yml +5 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +48 -0
- data/Rakefile +6 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/bin/time_to_first_comment +5 -0
- data/lib/time_to_first_comment.rb +6 -0
- data/lib/time_to_first_comment/cli.rb +47 -0
- data/lib/time_to_first_comment/pull_requests_stats.rb +71 -0
- data/lib/time_to_first_comment/version.rb +3 -0
- data/time_to_first_comment.gemspec +30 -0
- metadata +175 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b111abb3ac5ecd9abaaade06d90e71c2e79e6cda
|
4
|
+
data.tar.gz: 8d22dc67dc85a63f98c0793eb14d4c17a02eb6a7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 08d626ac6c7cee49e30cc03db9f334a5db722e6b25caa550e4e043f6e85fe7034f7dab47e27e09718d50ab091b817a53cc408168f19a49cf91decacfa31be2ef
|
7
|
+
data.tar.gz: d0ccf06ba30cf5febf0b63d89fffe0f3afcf8fa3ae755af11bcc4de270619aa24ae763b6f3ffdb2a0d2bd15d27e64832aa621ae3376712f091dcdc397d087124
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rubocop.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Julio Olivera
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Time To First Comment
|
2
|
+
|
3
|
+
Know how much it took for PRs on a repo to get their first comment.
|
4
|
+
|
5
|
+
# Usage
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install time_to_first_comment
|
9
|
+
```
|
10
|
+
|
11
|
+
## CLI
|
12
|
+
|
13
|
+
The gem comes bundled with a CLI to quickly get data for a repo:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ time_to_first_comment --repo someuser/somerepo --from 2015-12-01 --to 2015-12-15
|
17
|
+
Some pull request: No comments yet.
|
18
|
+
Some other pull request: 17 hrs 21 mins 2 secs until first comment.
|
19
|
+
```
|
20
|
+
|
21
|
+
Available options:
|
22
|
+
|
23
|
+
```
|
24
|
+
$ time_to_first_comment
|
25
|
+
Usage: time_to_first_comment [options]
|
26
|
+
-r, --repo Repository to look for PRs on
|
27
|
+
--from PRs created since this date - YYYY-MM-DD
|
28
|
+
--to PRs created up to this date - YYYY-MM-DD
|
29
|
+
-e, --endpoint Custom API endpoint to connect to Github Enterprise
|
30
|
+
-t, --token Access Token to query Github as a specific user
|
31
|
+
```
|
32
|
+
|
33
|
+
## API
|
34
|
+
|
35
|
+
You can use the gem in your own code to use the data any way you want:
|
36
|
+
|
37
|
+
```
|
38
|
+
require 'time_to_first_comment'
|
39
|
+
|
40
|
+
# You have to pass an instance of Octokit::Client that the gem will use to query Github.
|
41
|
+
# This way, you can configure that instance any way you like.
|
42
|
+
stats = TimeToFirstComment::PullRequestsStats.new(Octokit::Client.new)
|
43
|
+
|
44
|
+
stats.time_to_first_comment('someuser/somerepo').each do |pull, seconds|
|
45
|
+
# Here `pull` is an instance of Sawyer::Resource returned by Octokit::Client.
|
46
|
+
# `seconds` is the number of seconds until that PR got its first comment, or nil if there were none yet.
|
47
|
+
end
|
48
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'time_to_first_comment'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
require 'pry'
|
10
|
+
Pry.start
|
data/bin/setup
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'octokit'
|
2
|
+
require 'chronic_duration'
|
3
|
+
require 'slop'
|
4
|
+
|
5
|
+
module TimeToFirstComment
|
6
|
+
class Cli
|
7
|
+
def respond(arguments)
|
8
|
+
opts = Slop.parse(arguments) do
|
9
|
+
on :r, :repo=, 'Repository to look for PRs on'
|
10
|
+
on :from=, 'PRs created since this date - YYYY-MM-DD', argument: :optional
|
11
|
+
on :to=, 'PRs created up to this date - YYYY-MM-DD', argument: :optional
|
12
|
+
on :e, :endpoint=, 'Custom API endpoint to connect to Github Enterprise', argument: :optional
|
13
|
+
on :t, :token=, 'Access Token to query Github as a specific user', argument: :optional
|
14
|
+
end
|
15
|
+
|
16
|
+
unless opts.map(&:value).compact.any?
|
17
|
+
puts opts.help
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
if opts.missing.include?('repo')
|
22
|
+
puts 'Missing repository.'
|
23
|
+
puts opts.help
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
stats = TimeToFirstComment::PullRequestsStats.new(octokit_client(endpoint: opts[:endpoint], token: opts[:token]))
|
28
|
+
|
29
|
+
stats.time_to_first_comment(opts[:repo], from: opts[:from], to: opts[:to]).each do |pull, seconds|
|
30
|
+
if seconds
|
31
|
+
puts %(#{pull.title}: #{ChronicDuration.output(seconds)} until first comment.)
|
32
|
+
else
|
33
|
+
puts %(#{pull.title}: No comments yet.)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def octokit_client(endpoint:, token:)
|
41
|
+
options = {}
|
42
|
+
options[:api_endpoint] = endpoint if endpoint
|
43
|
+
options[:access_token] = token if token
|
44
|
+
Octokit::Client.new(options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module TimeToFirstComment
|
2
|
+
class PullRequestsStats
|
3
|
+
attr_accessor :client
|
4
|
+
|
5
|
+
# Creates a new instance of the stats generator.
|
6
|
+
#
|
7
|
+
# @param client [Octokit::Client]
|
8
|
+
def initialize(client)
|
9
|
+
self.client = client
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets the time until the first comment for a given repo's pull requests.
|
13
|
+
#
|
14
|
+
# @param repo [String] A string supported by {Octokit::Client} like 'username/repo'
|
15
|
+
# @param options [Hash] Options for selecting the PRs to check.
|
16
|
+
# @option options [String] :from PRs created starting from this date. The format is YYYY-MM-DD.
|
17
|
+
# @option options [String] :to PRs created up to this date. The format is YYYY-MM-DD.
|
18
|
+
# @return [Array<Array>] An array with tuples that include the pull request as the first parameter and the number of seconds
|
19
|
+
# until the first comment arrived as the second (`nil` if there are no comments).
|
20
|
+
# @example Get the time to first comment for the PRs in the repo 'username/repo'
|
21
|
+
# client = TimeToFirstComment::PullRequestsStats.new(Octokit::Client.new)
|
22
|
+
# client.time_to_first_comment('username/repo', from: '2015-03-12', to: '2015-05-10')
|
23
|
+
# #=> [[<Sawyer::Resource ...>, 12000], [<Sawyer::Resource ...>, nil]]
|
24
|
+
def time_to_first_comment(repo, options = {})
|
25
|
+
repo_query = "repo:#{repo}"
|
26
|
+
date_range_query = date_query(:created, options[:from], options[:to])
|
27
|
+
|
28
|
+
pulls = client.search_issues("type:pr sort:updated #{repo_query} #{date_range_query}")[:items]
|
29
|
+
|
30
|
+
pulls.map do |pull|
|
31
|
+
[pull, seconds_until_first_comment(repo, pull)]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Given a Pull Request ({Sawyer::Resource}) and the repo it belongs to it returns the number of seconds until the first
|
38
|
+
# comment happened, or `nil` if there were none.
|
39
|
+
#
|
40
|
+
# @param repo [String] The name of the repo the PR belongs to.
|
41
|
+
# @param pull [Sawyer::Resource] A Pull Request from {Octokit}.
|
42
|
+
# @return [Fixnum] The number of seconds until that PRs first comment, or `nil`.
|
43
|
+
def seconds_until_first_comment(repo, pull)
|
44
|
+
issue_comments = pull.rels[:comments].get.data
|
45
|
+
review_comments = client.review_comments(repo, pull.number)
|
46
|
+
first_comment = (issue_comments + review_comments).sort_by(&:created_at).first
|
47
|
+
first_comment.created_at - pull.created_at if first_comment
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns a query string for searching Github's API. It can be either for date created or updated, and with from and/or to
|
51
|
+
# dates.
|
52
|
+
#
|
53
|
+
# @param [Symbol] type Either :created or :updated
|
54
|
+
# @param [String] from Date from, the format is YYYY-MM-DD.
|
55
|
+
# @param [String] to Date to, the format is YYYY-MM-DD.
|
56
|
+
# @return [String] description A string for querying Github's API. An empty string if no date is provided.
|
57
|
+
def date_query(type, from, to)
|
58
|
+
if from && to
|
59
|
+
dates = "#{from}..#{to}"
|
60
|
+
elsif from
|
61
|
+
dates = ">=#{from}"
|
62
|
+
elsif to
|
63
|
+
dates = "<=#{to}"
|
64
|
+
else
|
65
|
+
return ''
|
66
|
+
end
|
67
|
+
|
68
|
+
"#{type}:#{dates}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'time_to_first_comment/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'time_to_first_comment'
|
8
|
+
spec.version = TimeToFirstComment::VERSION
|
9
|
+
spec.authors = ['Julio Olivera']
|
10
|
+
spec.email = ['julio.olvr@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = 'Utility to check how much time passed until the first comment was added to a Pull Request'
|
13
|
+
spec.homepage = 'https://github.com/julioolvr/time-to-first-comment'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = 'bin'
|
18
|
+
spec.executables = ['time_to_first_comment']
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'octokit', '~> 4.2'
|
22
|
+
spec.add_dependency 'chronic_duration', '~> 0.10'
|
23
|
+
spec.add_dependency 'slop', '~> 3.0'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.11'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
|
+
spec.add_development_dependency 'rubocop', '~> 0.35'
|
29
|
+
spec.add_development_dependency 'pry', '~> 0.10'
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: time_to_first_comment
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Julio Olivera
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: octokit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: chronic_duration
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.10'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: slop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.11'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.11'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.35'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.35'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.10'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.10'
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- julio.olvr@gmail.com
|
128
|
+
executables:
|
129
|
+
- time_to_first_comment
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- ".gitignore"
|
134
|
+
- ".rspec"
|
135
|
+
- ".rubocop.yml"
|
136
|
+
- CHANGELOG.md
|
137
|
+
- Gemfile
|
138
|
+
- LICENSE.txt
|
139
|
+
- README.md
|
140
|
+
- Rakefile
|
141
|
+
- bin/console
|
142
|
+
- bin/setup
|
143
|
+
- bin/time_to_first_comment
|
144
|
+
- lib/time_to_first_comment.rb
|
145
|
+
- lib/time_to_first_comment/cli.rb
|
146
|
+
- lib/time_to_first_comment/pull_requests_stats.rb
|
147
|
+
- lib/time_to_first_comment/version.rb
|
148
|
+
- time_to_first_comment.gemspec
|
149
|
+
homepage: https://github.com/julioolvr/time-to-first-comment
|
150
|
+
licenses:
|
151
|
+
- MIT
|
152
|
+
metadata: {}
|
153
|
+
post_install_message:
|
154
|
+
rdoc_options: []
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
requirements: []
|
168
|
+
rubyforge_project:
|
169
|
+
rubygems_version: 2.4.6
|
170
|
+
signing_key:
|
171
|
+
specification_version: 4
|
172
|
+
summary: Utility to check how much time passed until the first comment was added to
|
173
|
+
a Pull Request
|
174
|
+
test_files: []
|
175
|
+
has_rdoc:
|