time_to_first_comment 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,4 @@
1
+ Gemfile.lock
2
+ pkg/
3
+ .yardoc/
4
+ time_to_first_comment-0.1.0.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ Style/Documentation:
2
+ Enabled: false
3
+
4
+ Metrics/LineLength:
5
+ Max: 130
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 0.1.0
2
+
3
+ * First release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in time_to_first_comment.gemspec
4
+ gemspec
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
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
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,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'time_to_first_comment'
4
+
5
+ TimeToFirstComment::Cli.new.respond(ARGV)
@@ -0,0 +1,6 @@
1
+ require 'time_to_first_comment/version'
2
+ require 'time_to_first_comment/pull_requests_stats'
3
+ require 'time_to_first_comment/cli'
4
+
5
+ module TimeToFirstComment
6
+ end
@@ -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,3 @@
1
+ module TimeToFirstComment
2
+ VERSION = '0.1.0'
3
+ 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: