how_is 19.0.0 → 20.0.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.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +1 -0
  3. data/.rubocop.yml +16 -0
  4. data/CHANGELOG.md +30 -3
  5. data/Gemfile +0 -6
  6. data/README.md +5 -2
  7. data/exe/how_is +7 -2
  8. data/fixtures/vcr_cassettes/how-is-example-empty-repository.yml +446 -727
  9. data/fixtures/vcr_cassettes/how-is-example-repository.yml +508 -727
  10. data/fixtures/vcr_cassettes/how-is-from-config-frontmatter.yml +43522 -1218
  11. data/fixtures/vcr_cassettes/how-is-how-is-travis-api-repos-builds.yml +287 -0
  12. data/fixtures/vcr_cassettes/how-is-with-config-file.yml +44307 -23286
  13. data/fixtures/vcr_cassettes/how_is_contributions_additions_count.yml +307 -0
  14. data/fixtures/vcr_cassettes/how_is_contributions_all_contributors.yml +81 -0
  15. data/fixtures/vcr_cassettes/how_is_contributions_changed_files.yml +307 -0
  16. data/fixtures/vcr_cassettes/how_is_contributions_changes.yml +307 -0
  17. data/fixtures/vcr_cassettes/how_is_contributions_commits.yml +307 -0
  18. data/fixtures/vcr_cassettes/how_is_contributions_compare_url.yml +74 -0
  19. data/fixtures/vcr_cassettes/how_is_contributions_deletions_count.yml +307 -0
  20. data/fixtures/vcr_cassettes/how_is_contributions_new_contributors.yml +234 -0
  21. data/fixtures/vcr_cassettes/how_is_contributions_summary.yml +378 -0
  22. data/fixtures/vcr_cassettes/how_is_contributions_summary_2.yml +378 -0
  23. data/fixtures/vcr_cassettes/how_is_fetcher_call.yml +572 -0
  24. data/how_is.gemspec +3 -2
  25. data/lib/how_is/cli.rb +4 -6
  26. data/lib/how_is/frontmatter.rb +46 -0
  27. data/lib/how_is/report.rb +59 -63
  28. data/lib/how_is/sources/github/contributions.rb +164 -0
  29. data/lib/how_is/sources/github/issues.rb +142 -0
  30. data/lib/how_is/sources/github/pulls.rb +20 -0
  31. data/lib/how_is/sources/github.rb +11 -0
  32. data/lib/how_is/sources/github_helpers.rb +191 -0
  33. data/lib/how_is/sources/travis.rb +34 -0
  34. data/lib/how_is/sources.rb +9 -0
  35. data/lib/how_is/templates/issues_or_pulls_partial.html_template +7 -0
  36. data/lib/how_is/templates/report.html_template +27 -0
  37. data/lib/how_is/templates/report_partial.html_template +12 -0
  38. data/lib/how_is/version.rb +2 -2
  39. data/lib/how_is.rb +59 -158
  40. metadata +42 -16
  41. data/lib/how_is/analyzer.rb +0 -222
  42. data/lib/how_is/builds.rb +0 -36
  43. data/lib/how_is/contributions.rb +0 -156
  44. data/lib/how_is/fetcher.rb +0 -77
  45. data/lib/how_is/pulse.rb +0 -47
  46. data/lib/how_is/report/base_report.rb +0 -148
  47. data/lib/how_is/report/html.rb +0 -120
  48. data/lib/how_is/report/json.rb +0 -34
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "how_is/sources/github"
4
+ require "date"
5
+
6
+ module HowIs
7
+ module Sources
8
+ module GithubHelpers
9
+ def obj_to_array_of_hashes(object)
10
+ object.to_a.map(&:to_h)
11
+ end
12
+
13
+ # Given an Array of issues or pulls, return a Hash specifying how many
14
+ # issues or pulls use each label.
15
+ def num_with_label(issues_or_pulls)
16
+ # Returned hash maps labels to frequency.
17
+ # E.g., given 10 issues/pulls with label "label1" and 5 with label "label2",
18
+ # {
19
+ # "label1" => 10,
20
+ # "label2" => 5
21
+ # }
22
+
23
+ hash = Hash.new(0)
24
+ issues_or_pulls.each do |iop|
25
+ next unless iop["labels"]
26
+
27
+ iop["labels"].each do |label|
28
+ hash[label["name"]] += 1
29
+ end
30
+ end
31
+ hash
32
+ end
33
+
34
+ # Returns the number of issues with no label.
35
+ def num_with_no_label(issues)
36
+ issues.select { |x| x["labels"].empty? }.length
37
+ end
38
+
39
+ # Given an Array of dates, average the timestamps and return the date that
40
+ # represents.
41
+ def average_date_for(issues_or_pulls)
42
+ timestamps = issues_or_pulls.map { |iop| DateTime.parse(iop["created_at"]).strftime("%s").to_i }
43
+ average_timestamp = timestamps.reduce(:+) / issues_or_pulls.length
44
+
45
+ DateTime.strptime(average_timestamp.to_s, "%s")
46
+ end
47
+
48
+ # Given an Array of issues or pulls, return the average age of them.
49
+ # Returns nil if no issues or pulls are provided.
50
+ def average_age_for(issues_or_pulls)
51
+ return nil if issues_or_pulls.empty?
52
+
53
+ ages = issues_or_pulls.map { |iop| time_ago_in_seconds(iop["created_at"]) }
54
+ average_age_in_seconds = ages.reduce(:+) / ages.length
55
+
56
+ values = period_pairs_for(average_age_in_seconds).reject { |(v, _)| v.zero? }.map { |(v, k)|
57
+ k += "s" if v != 1
58
+ [v, k]
59
+ }
60
+
61
+ most_significant = values[0, 2].map { |x| x.join(" ") }
62
+
63
+ value =
64
+ if most_significant.length < 2
65
+ most_significant.first
66
+ else
67
+ most_significant.join(" and ")
68
+ end
69
+
70
+ "approximately #{value}"
71
+ end
72
+
73
+ def sort_iops_by_created_at(issues_or_pulls)
74
+ issues_or_pulls.sort_by { |x| DateTime.parse(x["created_at"]) }
75
+ end
76
+
77
+ # Given an Array of issues or pulls, return the oldest.
78
+ # Returns nil if no issues or pulls are provided.
79
+ def oldest_for(issues_or_pulls)
80
+ return nil if issues_or_pulls.empty?
81
+
82
+ iop = sort_iops_by_created_at(issues_or_pulls).first
83
+
84
+ {
85
+ created_at: iop["created_at"],
86
+ link: iop["html_url"],
87
+ }
88
+ end
89
+
90
+ # Given an Array of issues or pulls, return the newest.
91
+ # Returns nil if no issues or pulls are provided.
92
+ def newest_for(issues_or_pulls)
93
+ return nil if issues_or_pulls.empty?
94
+
95
+ iop = sort_iops_by_created_at(issues_or_pulls).last
96
+
97
+ {
98
+ created_at: iop["created_at"],
99
+ link: iop["html_url"],
100
+ }
101
+ end
102
+
103
+ # Given an issue or PR, returns the date it was created.
104
+ def date_for(issue_or_pull)
105
+ DateTime.parse(issue_or_pull["created_at"])
106
+ end
107
+
108
+ private
109
+
110
+ # Takes an Array of labels, and returns amodified list that includes links
111
+ # to each label.
112
+ def with_label_links(labels, repository)
113
+ labels.map { |label, num_issues|
114
+ label_link = "https://github.com/#{repository}/issues?q=" + CGI.escape("is:open is:issue label:\"#{label}\"")
115
+
116
+ [label, {"link" => label_link, "total" => num_issues}]
117
+ }.to_h
118
+ end
119
+
120
+ # Returns how many seconds ago a date (as a String) was.
121
+ def time_ago_in_seconds(x)
122
+ DateTime.now.strftime("%s").to_i - DateTime.parse(x).strftime("%s").to_i
123
+ end
124
+
125
+ def issue_or_pull_to_hash(iop)
126
+ return nil if iop.nil?
127
+
128
+ ret = {}
129
+
130
+ ret["html_url"] = iop["html_url"]
131
+ ret["number"] = iop["number"]
132
+ ret["date"] = date_for(iop)
133
+
134
+ ret
135
+ end
136
+
137
+ SECONDS_IN_A_YEAR = 31_556_926
138
+ SECONDS_IN_A_MONTH = 2_629_743
139
+ SECONDS_IN_A_WEEK = 604_800
140
+ SECONDS_IN_A_DAY = 86_400
141
+
142
+ # Calculates a list of pairs of value and period label.
143
+ #
144
+ # @param age_in_seconds [Float]
145
+ #
146
+ # @return [Array<Array>] The input age_in_seconds expressed as different
147
+ # units, as pairs of value and unit name.
148
+ def period_pairs_for(age_in_seconds)
149
+ years_remainder = age_in_seconds % SECONDS_IN_A_YEAR
150
+
151
+ months_remainder = years_remainder % SECONDS_IN_A_MONTH
152
+
153
+ weeks_remainder = months_remainder % SECONDS_IN_A_WEEK
154
+
155
+ [
156
+ [age_in_seconds / SECONDS_IN_A_YEAR, "year"],
157
+ [years_remainder / SECONDS_IN_A_MONTH, "month"],
158
+ [months_remainder / SECONDS_IN_A_WEEK, "week"],
159
+ [weeks_remainder / SECONDS_IN_A_DAY, "day"],
160
+ ]
161
+ end
162
+
163
+ def pluralize(string, number, zero_is_no: false)
164
+ number_str = number
165
+ number_str = "no" if number.zero? && zero_is_no
166
+
167
+ "#{number_str} #{string}#{(number == 1) ? '' : 's'}"
168
+ end
169
+
170
+ def are_or_is(number)
171
+ if number == 1
172
+ "is"
173
+ else
174
+ "are"
175
+ end
176
+ end
177
+
178
+ def pretty_date(date_or_str)
179
+ if date_or_str.is_a?(DateTime)
180
+ date = datetime_or_str
181
+ elsif date_or_str.is_a?(String)
182
+ date = DateTime.parse(date_or_str)
183
+ else
184
+ raise ArgumentError, "expected DateTime or String, got #{date_or_str.class}"
185
+ end
186
+
187
+ date.strftime("%b %_d, %Y")
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "okay/http"
4
+ require "how_is/sources/github"
5
+
6
+ module HowIs::Sources
7
+ # Fetches metadata about CI builds from travis-ci.org.
8
+ class Travis
9
+ # @param repository [String] GitHub repository name, of the format user/repo.
10
+ # @param end_date [String] End date for the report being generated.
11
+ def initialize(repository, end_date)
12
+ @repository = repository
13
+ # TODO: Do something with end_date.
14
+ # TODO: Figure out Default Branch of the repo
15
+ end
16
+
17
+ def builds
18
+ JSON.parse(fetch_builds)
19
+ end
20
+
21
+ private
22
+
23
+ # Returns API result of /repos/:user/:repo/builds for Push type Travis
24
+ # events.
25
+ #
26
+ # @return [String] JSON result
27
+ def fetch_builds
28
+ Okay::HTTP.get(
29
+ "http://api.travis-ci.org/repos/#{@repository}/builds?event_type=push",
30
+ headers: {"Accept" => "application/vnd.travis-ci.2+json"}
31
+ ).body
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "how_is/version"
4
+
5
+ module HowIs
6
+ module Sources
7
+ # Simply for creating a namespace.
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ %{summary}
2
+
3
+ <ul>
4
+ <li>Average age: %{average_age}.</li>
5
+ <li><a href="%{oldest_link}">Oldest %{pretty_type}</a> was opened on %{oldest_date}.</li>
6
+ <li><a href="%{newest_link}">Newest %{pretty_type}</a> was opened on %{newest_date}.</li>
7
+ </ul>
@@ -0,0 +1,27 @@
1
+ %{frontmatter}<!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>%{title}</title>
5
+ <style>
6
+ body { font: sans-serif; }
7
+ main {
8
+ max-width: 600px;
9
+ max-width: 72ch;
10
+ margin: auto;
11
+ }
12
+ .horizontal-bar-graph {
13
+ position: relative;
14
+ width: 100%%; /* lol Kernel.format() disapproves. */
15
+ }
16
+ .horizontal-bar-graph .fill {
17
+ display: inline-block;
18
+ background: #CCC;
19
+ }
20
+ </style>
21
+ </head>
22
+ <body>
23
+ <main>
24
+ %{report}
25
+ </main>
26
+ </body>
27
+ </html>
@@ -0,0 +1,12 @@
1
+ %{frontmatter}
2
+ <h1>%{title}</h1>
3
+ <p>%{contributions_summary}</p>
4
+
5
+ <h2>Pull Requests</h2>
6
+ %{pulls_summary}
7
+
8
+ <h2>Issues</h2>
9
+ %{issues_summary}
10
+
11
+ <h2>Issues Per Label</h2>
12
+ %{issues_per_label}
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class HowIs
4
- VERSION = "19.0.0"
3
+ module HowIs
4
+ VERSION = "20.0.0"
5
5
  end
data/lib/how_is.rb CHANGED
@@ -1,54 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "how_is/version"
4
- require "contracts"
5
- require "cacert"
4
+ require "how_is/report"
5
+ require "github_api"
6
6
 
7
- Cacert.set_in_env
7
+ module HowIs
8
+ DEFAULT_REPORT_FILE = "report.html"
8
9
 
9
- C = Contracts
10
-
11
- # HowIs control class used from the CLI tool.
12
- #
13
- # Generates an analysis and has methods to build reports from it.
14
- class HowIs
15
- include Contracts::Core
16
-
17
- require "how_is/fetcher"
18
- require "how_is/analyzer"
19
- require "how_is/report"
20
-
21
- DEFAULT_FORMAT = :html
22
-
23
- ##
24
- # Generate a HowIs instance, so you can generate reports.
25
- #
26
- # @param repository [String] The name of a GitHub repository (of the
27
- # format <user or organization>/<repository>).
28
- # @param analysis [HowIs::Analysis] Optional; if passed, this Analysis
29
- # object is used instead of generating one.
30
- def initialize(repository, analysis = nil, **kw_args)
31
- # If no Analysis is passed, generate one.
32
- analysis ||= HowIs.generate_analysis(repository: repository, **kw_args)
33
-
34
- # Used by to_html, to_json, etc.
35
- @analysis = analysis
10
+ def self.new(repository, date)
11
+ Report.new(repository, date)
36
12
  end
37
13
 
38
- ##
39
- # Generate an HTML report.
40
- #
41
- # @return [String] An HTML report.
42
- def to_html
43
- Report.export(@analysis, :html)
44
- end
45
-
46
- ##
47
- # Generate a JSON report.
48
- #
49
- # @return [String] A JSON report.
50
- def to_json
51
- Report.export(@analysis, :json)
14
+ def self.github
15
+ @@github ||=
16
+ Github.new(auto_pagination: true) do |config|
17
+ config.basic_auth = ENV["HOWIS_BASIC_AUTH"] if ENV["HOWIS_BASIC_AUTH"]
18
+ end
52
19
  end
53
20
 
54
21
  ##
@@ -70,140 +37,62 @@ class HowIs
70
37
  # @return [HowIs] A HowIs object that can be used for generating other
71
38
  # reports, treating the provided report data as a cache.
72
39
  def self.from_hash(data)
73
- analysis = HowIs::Analyzer.from_hash(data)
40
+ analysis = HowIs::Analysis.from_hash(data)
74
41
 
75
42
  new(analysis.repository, analysis)
76
43
  end
77
44
 
78
- ##
79
- # Returns a list of possible export formats.
80
- #
81
- # @return [Array<String>] An array of the types of reports you can
82
- # generate.
83
- def self.supported_formats
84
- report_constants = HowIs.constants.grep(/.Report/) - [:BaseReport]
85
- report_constants.map { |x| x.to_s.split("Report").first.downcase }
86
- end
87
-
88
- ##
89
- # Returns whether or not the specified +file+ can be exported to.
90
- #
91
- # @param file [String] A filename.
92
- # @return [Boolean] +true+ if HowIs can export to the file, +false+
93
- # if it can't.
94
- def self.can_export_to?(file)
95
- # TODO: Check if the file is writable?
96
- supported_formats.include?(file.split(".").last)
97
- end
98
-
99
- # Generate an analysis.
100
- # TODO: This may make more sense as Analysis.new().
101
- # TODO: Nothing overrides +fetcher+ and +analyzer+. Remove ability to do so.
102
- # FIXME: THIS CODE AND EVERYTHING ASSOCIATED WITH IT IS A FUCKING ATROCITY.
103
- Contract C::KeywordArgs[repository: String,
104
- fetcher: C::Optional[Class],
105
- analyzer: C::Optional[Class],
106
- github: C::Optional[C::Any]] => C::Any
107
- def self.generate_analysis(repository:,
108
- fetcher: Fetcher.new,
109
- analyzer: Analyzer.new,
110
- github: nil)
111
- raw_data = fetcher.call(repository, github)
112
- analysis = analyzer.call(raw_data)
113
-
114
- analysis
115
- end
116
-
117
- # Generates YAML frontmatter, as is used in Jekyll and other blog engines.
118
- #
119
- # E.g.,
120
- # generate_frontmatter({'foo' => "bar %{baz}"}, {'baz' => "asdf"})
121
- # => "---\nfoo: bar asdf\n"
122
- Contract C::HashOf[C::Or[String, Symbol] => String],
123
- C::HashOf[C::Or[String, Symbol] => C::Any] => String
124
- def self.generate_frontmatter(frontmatter, report_data)
125
- frontmatter = convert_keys(frontmatter, :to_s)
126
- report_data = convert_keys(report_data, :to_sym)
127
-
128
- frontmatter = frontmatter.map { |k, v|
129
- # Sometimes report_data has unused keys, which generates a warning, but
130
- # we're okay with it.
131
- v = silence_warnings { v % report_data }
132
-
133
- [k, v]
134
- }.to_h
135
-
136
- YAML.dump(frontmatter)
137
- end
138
-
139
45
  ##
140
46
  # Generates a series of report files based on a config Hash.
141
47
  #
142
48
  # @param config [Hash] A Hash specifying the formats, locations, etc
143
49
  # of the reports to generate.
144
- # @param github (You don't need this.) An object to replace the GitHub
145
- # class when fetching data.
146
- # @param report_class (You don't need this.) An object to replace the
147
- # HowIs::Report class when generating reports.
148
- def self.from_config(config,
149
- github: nil,
150
- report_class: nil)
151
- report_class ||= HowIs::Report
152
-
153
- date = Date.strptime(Time.now.to_i.to_s, "%s")
154
- friendly_date = date.strftime("%B %d, %y")
155
-
156
- analysis = HowIs.generate_analysis(repository: config["repository"], github: github)
157
-
158
- report_data = {
159
- repository: config["repository"],
160
- date: date,
161
- friendly_date: friendly_date,
162
- }
163
-
164
- generated_reports = {}
50
+ # @param date [String] A string containing the date (YYYY-MM-DD) that the
51
+ # report ends on. E.g., for Jan 1-Feb 1 2017, you'd pass 2017-02-01.
52
+ def self.from_config(config, date)
53
+ report = Report.new(config["repository"], date)
54
+ report_data = prepare_report_metadata(config["repository"], date)
165
55
 
166
- config["reports"].map do |format, report_config|
167
- # Sometimes report_data has unused keys, which generates a warning, but
168
- # we're okay with it.
169
- filename = silence_warnings { report_config["filename"] % report_data }
170
- file = File.join(report_config["directory"], filename)
56
+ generated_reports =
57
+ config["reports"].map { |format, report_config|
58
+ # Sometimes report_data has unused keys, which generates a warning, but
59
+ # we're okay with it, so we wrap it with silence_warnings {}.
60
+ filename = silence_warnings { report_config["filename"] % report_data }
61
+ file = File.join(report_config["directory"], filename)
171
62
 
172
- report = report_class.export(analysis, format)
63
+ report_export = report.send("to_#{format}", report_config["frontmatter"])
173
64
 
174
- result = build_report(report_config["frontmatter"], report_data, report)
65
+ [file, report_export]
66
+ }
175
67
 
176
- generated_reports[file] = result
177
-
178
- result
179
- end
180
-
181
- generated_reports
68
+ generated_reports.to_h
182
69
  end
183
70
 
184
- # Combine the frontmatter, report data, and raw report into a report with
185
- # frontmatter.
186
- def self.build_report(frontmatter, report_data, report)
187
- str = StringIO.new
188
-
189
- if frontmatter
190
- str.puts generate_frontmatter(frontmatter, report_data)
191
- str.puts "---"
192
- str.puts
193
- end
71
+ ##
72
+ # Returns a list of possible export formats.
73
+ #
74
+ # @return [Array<String>] An array of the types of reports you can generate.
75
+ def self.supported_formats
76
+ ["html", "json"]
77
+ end
194
78
 
195
- str.puts report
79
+ def self.template(filename)
80
+ dir = File.expand_path("./how_is/templates/", __dir__)
81
+ path = File.join(dir, filename)
196
82
 
197
- str.string
83
+ open(path).read
198
84
  end
199
85
 
200
- # @example
201
- # convert_keys({'foo' => 'bar'}, :to_sym)
202
- # # => {:foo => 'bar'}
203
- def self.convert_keys(data, method_name)
204
- data.map { |k, v| [k.send(method_name), v] }.to_h
86
+ ##
87
+ # Returns whether or not the specified +file+ can be exported to.
88
+ #
89
+ # @param file [String] A filename.
90
+ # @return [Boolean] +true+ if HowIs can export to the file, +false+
91
+ # if it can't.
92
+ def self.can_export_to?(file)
93
+ # TODO: Check if the file is writable?
94
+ supported_formats.include?(file.split(".").last)
205
95
  end
206
- private_class_method :convert_keys
207
96
 
208
97
  def self.silence_warnings(&block)
209
98
  with_warnings(nil, &block)
@@ -218,4 +107,16 @@ class HowIs
218
107
  $VERBOSE = old_verbose
219
108
  end
220
109
  private_class_method :with_warnings
110
+
111
+ def self.prepare_report_metadata(repository, date)
112
+ end_date = DateTime.strptime(date, "%Y-%m-%d")
113
+ friendly_end_date = end_date.strftime("%B %d, %y")
114
+
115
+ {
116
+ repository: repository,
117
+ date: end_date,
118
+ friendly_date: friendly_end_date,
119
+ }
120
+ end
121
+ private_class_method :prepare_report_metadata
221
122
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: how_is
3
3
  version: !ruby/object:Gem::Version
4
- version: 19.0.0
4
+ version: 20.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ellen Marie Dash
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-16 00:00:00.000000000 Z
11
+ date: 2017-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: github_api
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.17.0
19
+ version: 0.18.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.17.0
26
+ version: 0.18.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: contracts
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.16.0
41
41
  - !ruby/object:Gem::Dependency
42
- name: tessellator-fetcher
42
+ name: okay
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 5.0.2
47
+ version: 4.0.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 5.0.2
54
+ version: 4.0.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: pry
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
167
181
  description:
168
182
  email:
169
183
  - me@duckie.co
@@ -197,21 +211,33 @@ files:
197
211
  - fixtures/vcr_cassettes/how-is-from-config-frontmatter.yml
198
212
  - fixtures/vcr_cassettes/how-is-how-is-travis-api-repos-builds.yml
199
213
  - fixtures/vcr_cassettes/how-is-with-config-file.yml
214
+ - fixtures/vcr_cassettes/how_is_contributions_additions_count.yml
200
215
  - fixtures/vcr_cassettes/how_is_contributions_all_contributors.yml
216
+ - fixtures/vcr_cassettes/how_is_contributions_changed_files.yml
217
+ - fixtures/vcr_cassettes/how_is_contributions_changes.yml
218
+ - fixtures/vcr_cassettes/how_is_contributions_commits.yml
219
+ - fixtures/vcr_cassettes/how_is_contributions_compare_url.yml
201
220
  - fixtures/vcr_cassettes/how_is_contributions_default_branch.yml
221
+ - fixtures/vcr_cassettes/how_is_contributions_deletions_count.yml
202
222
  - fixtures/vcr_cassettes/how_is_contributions_new_contributors.yml
223
+ - fixtures/vcr_cassettes/how_is_contributions_summary.yml
224
+ - fixtures/vcr_cassettes/how_is_contributions_summary_2.yml
225
+ - fixtures/vcr_cassettes/how_is_fetcher_call.yml
203
226
  - how_is.gemspec
204
227
  - lib/how_is.rb
205
- - lib/how_is/analyzer.rb
206
- - lib/how_is/builds.rb
207
228
  - lib/how_is/cli.rb
208
- - lib/how_is/contributions.rb
209
- - lib/how_is/fetcher.rb
210
- - lib/how_is/pulse.rb
229
+ - lib/how_is/frontmatter.rb
211
230
  - lib/how_is/report.rb
212
- - lib/how_is/report/base_report.rb
213
- - lib/how_is/report/html.rb
214
- - lib/how_is/report/json.rb
231
+ - lib/how_is/sources.rb
232
+ - lib/how_is/sources/github.rb
233
+ - lib/how_is/sources/github/contributions.rb
234
+ - lib/how_is/sources/github/issues.rb
235
+ - lib/how_is/sources/github/pulls.rb
236
+ - lib/how_is/sources/github_helpers.rb
237
+ - lib/how_is/sources/travis.rb
238
+ - lib/how_is/templates/issues_or_pulls_partial.html_template
239
+ - lib/how_is/templates/report.html_template
240
+ - lib/how_is/templates/report_partial.html_template
215
241
  - lib/how_is/version.rb
216
242
  - roadmap.markdown
217
243
  homepage: https://github.com/how-is/how_is
@@ -234,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
260
  version: '0'
235
261
  requirements: []
236
262
  rubyforge_project:
237
- rubygems_version: 2.6.13
263
+ rubygems_version: 2.7.3
238
264
  signing_key:
239
265
  specification_version: 4
240
266
  summary: Quantify the health of a GitHub repository.