pig-ci-rails 0.2.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
- require 'bundler/gem_tasks'
1
+ require "bundler/gem_tasks"
2
2
  begin
3
- require 'rspec/core/rake_task'
3
+ require "rspec/core/rake_task"
4
4
 
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
@@ -1,10 +1,5 @@
1
1
  en:
2
2
  pig_ci:
3
- api:
4
- reports:
5
- success: 'PigCI: Successfully submitted report to pigci.com'
6
- error: 'Unable to connect to PigCI API: %{error}'
7
- api_error: 'Unable to connect to PigCI API'
8
3
  summary:
9
4
  ci_start: 'PigCI Thresholds Summary:'
10
5
  ci_failure: 'PigCI: This commit has exceeded the thresholds defined in PigCI.thresholds'
@@ -13,7 +8,7 @@ en:
13
8
  view_historic_reports: 'Historic Reports'
14
9
  footer_html: |
15
10
  <p>Generated <time datetime="%{generated_at}">%{generated_at}</time> by PigCI.</p>
16
- <p>Support <a href="https://pigci.com/" target="_blank" rel="noopener">PigCI</a> by <a href="https://github.com/apps/pigci/installations/new" target="_blank" rel="noopener">adding us on GitHub</a>.</p>
11
+ <p>Support <a href="https://pigci.mikerogers.io/" target="_blank" rel="noopener">PigCI</a> by <a href="https://www.buymeacoffee.com/MikeRogers0" target="_blank" rel="noopener">buying me a coffee</a>.</p>
17
12
 
18
13
  report:
19
14
  memory:
data/lib/pig_ci.rb CHANGED
@@ -1,30 +1,42 @@
1
- require 'active_support'
2
- require 'active_support/core_ext/string/inflections'
3
- require 'rake'
4
-
5
- require 'pig_ci/version'
6
- require 'pig_ci/api'
7
- require 'pig_ci/configuration'
8
- require 'pig_ci/decorator'
9
- require 'pig_ci/summary'
10
- require 'pig_ci/profiler_engine'
11
- require 'pig_ci/profiler'
12
- require 'pig_ci/metric'
13
- require 'pig_ci/report'
1
+ require "active_support"
2
+ require "active_support/core_ext/string/inflections"
3
+ require "rake"
4
+
5
+ require "pig_ci/version"
6
+ require "pig_ci/configuration"
7
+ require "pig_ci/decorator"
8
+ require "pig_ci/summary"
9
+ require "pig_ci/profiler_engine"
10
+ require "pig_ci/profiler"
11
+ require "pig_ci/metric"
12
+ require "pig_ci/report"
13
+ require "pig_ci/test_frameworks"
14
14
 
15
15
  module PigCI
16
16
  extend self
17
17
 
18
18
  attr_accessor :pid
19
19
 
20
+ attr_writer :enabled
21
+ def enabled?
22
+ @enabled.nil? ? true : @enabled
23
+ end
24
+
25
+ # Rails caches repeated queries within the same request. You can not count
26
+ # any cached queries if you'd like.
27
+ attr_writer :ignore_cached_queries
28
+ def ignore_cached_queries?
29
+ @ignore_cached_queries.nil? ? false : @ignore_cached_queries
30
+ end
31
+
20
32
  attr_writer :tmp_directory
21
33
  def tmp_directory
22
- @tmp_directory || Pathname.new(Dir.getwd).join('tmp', 'pig-ci')
34
+ @tmp_directory || Pathname.new(Dir.getwd).join("tmp", "pig-ci")
23
35
  end
24
36
 
25
37
  attr_writer :output_directory
26
38
  def output_directory
27
- @output_directory || Pathname.new(Dir.getwd).join('pig-ci')
39
+ @output_directory || Pathname.new(Dir.getwd).join("pig-ci")
28
40
  end
29
41
 
30
42
  attr_accessor :generate_terminal_summary
@@ -88,29 +100,19 @@ module PigCI
88
100
  @profiler_engine ||= PigCI::ProfilerEngine::Rails.new
89
101
  end
90
102
 
91
- attr_writer :api_base_uri
92
- def api_base_uri
93
- @api_base_uri || 'https://api.pigci.com/api'
94
- end
95
-
96
- attr_accessor :api_verify_ssl
97
- def api_verify_ssl?
98
- !@api_verify_ssl.nil? ? @api_verify_ssl : true
99
- end
100
-
101
- attr_accessor :api_key
102
- def api_key?
103
- !@api_key.nil? && @api_key != ''
104
- end
105
-
106
103
  attr_writer :commit_sha1
107
104
  def commit_sha1
108
- @commit_sha1 || ENV['CI_COMMIT_ID'] || ENV['CIRCLE_SHA1'] || ENV['TRAVIS_COMMIT'] || `git rev-parse HEAD`.strip
105
+ @commit_sha1 || ENV["CI_COMMIT_ID"] || ENV["CIRCLE_SHA1"] || ENV["TRAVIS_COMMIT"] || `git rev-parse HEAD`.strip
109
106
  end
110
107
 
111
108
  attr_writer :head_branch
112
109
  def head_branch
113
- @head_branch || ENV['CI_BRANCH'] || ENV['CIRCLE_BRANCH'] || ENV['TRAVIS_BRANCH'] || `git rev-parse --abbrev-ref HEAD`.strip
110
+ @head_branch || ENV["CI_BRANCH"] || ENV["CIRCLE_BRANCH"] || ENV["TRAVIS_BRANCH"] || `git rev-parse --abbrev-ref HEAD`.strip
111
+ end
112
+
113
+ # Throw deprecation notice for setting API
114
+ def api_key=(value)
115
+ puts "DEPRECATED: PigCI.com API has been retired, you no longer need to set config.api_key in your spec/rails_helper.rb file."
114
116
  end
115
117
 
116
118
  attr_writer :locale
@@ -130,8 +132,9 @@ module PigCI
130
132
 
131
133
  def start(&block)
132
134
  self.pid = Process.pid
135
+ PigCI::TestFrameworks::Rspec.configure! if defined?(::RSpec)
133
136
 
134
- block.call(self) if block_given?
137
+ block&.call(self)
135
138
 
136
139
  # Add our translations
137
140
  load_i18ns!
@@ -146,7 +149,7 @@ module PigCI
146
149
 
147
150
  def load_i18ns!
148
151
  I18n.available_locales << PigCI.locale
149
- I18n.load_path += Dir["#{File.expand_path('../config/locales/pig_ci', __dir__)}/*.{rb,yml}"]
152
+ I18n.load_path += Dir["#{File.expand_path("../config/locales/pig_ci", __dir__)}/*.{rb,yml}"]
150
153
  end
151
154
 
152
155
  def run_exit_tasks!
@@ -161,9 +164,6 @@ module PigCI
161
164
  # Save the report summary to the project root.
162
165
  PigCI::Summary::HTML.new(reports: profiler_engine.reports).save! if PigCI.generate_html_summary?
163
166
 
164
- # If they have an API key, share it with PigCI.com
165
- PigCI::Api::Reports.new(reports: profiler_engine.reports).share! if PigCI.api_key?
166
-
167
167
  # Make sure CI fails when metrics are over thresholds.
168
168
  PigCI::Summary::CI.new(reports: profiler_engine.reports).call!
169
169
  end
@@ -1,7 +1,7 @@
1
1
  class PigCI::Configuration
2
- Thresholds = Struct.new(:memory, :request_time, :database_request) do
2
+ Thresholds = Struct.new(:memory, :request_time, :database_request) {
3
3
  def initialize(memory: 350, request_time: 250, database_request: 35)
4
4
  super(memory, request_time, database_request)
5
5
  end
6
- end
6
+ }
7
7
  end
@@ -6,4 +6,4 @@ class PigCI::Decorator
6
6
  end
7
7
  end
8
8
 
9
- require 'pig_ci/decorator/report_terminal_decorator'
9
+ require "pig_ci/decorator/report_terminal_decorator"
@@ -1,4 +1,4 @@
1
- require 'colorized_string'
1
+ require "colorized_string"
2
2
 
3
3
  class PigCI::Decorator::ReportTerminalDecorator < PigCI::Decorator
4
4
  %i[key max min mean number_of_requests].each do |field|
@@ -8,9 +8,9 @@ class PigCI::Decorator::ReportTerminalDecorator < PigCI::Decorator
8
8
  end
9
9
 
10
10
  def max_change_percentage
11
- if @object[:max_change_percentage].start_with?('-')
11
+ if @object[:max_change_percentage].start_with?("-")
12
12
  ColorizedString[@object[:max_change_percentage]].colorize(:green)
13
- elsif @object[:max_change_percentage].start_with?('0.0')
13
+ elsif @object[:max_change_percentage].start_with?("0.0")
14
14
  @object[:max_change_percentage]
15
15
  else
16
16
  ColorizedString[@object[:max_change_percentage]].colorize(:red)
data/lib/pig_ci/metric.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  class PigCI::Metric; end
2
2
 
3
- require 'pig_ci/metric/current'
4
- require 'pig_ci/metric/historical'
3
+ require "pig_ci/metric/current"
4
+ require "pig_ci/metric/historical"
@@ -7,7 +7,7 @@ class PigCI::Metric::Current
7
7
  @to_h = {}
8
8
 
9
9
  File.foreach(@log_file) do |f|
10
- key, value = f.strip.split('|')
10
+ key, value = f.strip.split("|")
11
11
  value = value.to_i
12
12
 
13
13
  @to_h[key] ||= {
@@ -11,7 +11,7 @@ class PigCI::Metric::Historical::ChangePercentage
11
11
  previous_run_data = previous_run_data_for_key(data[:key]) || data
12
12
 
13
13
  data[:max_change_percentage] = (((BigDecimal(data[:max]) - BigDecimal(previous_run_data[:max])) / BigDecimal(previous_run_data[:max])) * 100).round(PigCI.max_change_percentage_precision)
14
- data[:max_change_percentage] = BigDecimal('0') if data[:max_change_percentage].to_s == 'NaN' || data[:max_change_percentage] == BigDecimal('-0.0')
14
+ data[:max_change_percentage] = BigDecimal("0") if data[:max_change_percentage].to_s == "NaN" || data[:max_change_percentage] == BigDecimal("-0.0")
15
15
  data[:max_change_percentage] = data[:max_change_percentage].to_f
16
16
 
17
17
  data
@@ -29,15 +29,15 @@ class PigCI::Metric::Historical
29
29
 
30
30
  def remove_old_historical_data!
31
31
  new_historical_data = @to_h
32
- .sort_by { |timestamp, _data| timestamp.to_s.to_i * -1 }[0..(PigCI.historical_data_run_limit - 1)]
33
- .to_h
34
- .sort_by { |timestamp, _data| timestamp.to_s.to_i * -1 }.to_h
32
+ .sort_by { |timestamp, _data| timestamp.to_s.to_i * -1 }[0..(PigCI.historical_data_run_limit - 1)]
33
+ .to_h
34
+ .sort_by { |timestamp, _data| timestamp.to_s.to_i * -1 }.to_h
35
35
  @to_h = new_historical_data
36
36
  end
37
37
 
38
38
  def read_historical_log_file
39
39
  if File.exist?(@historical_log_file)
40
- JSON.parse(File.open(@historical_log_file, 'r').read, symbolize_names: true)
40
+ JSON.parse(File.open(@historical_log_file, "r").read, symbolize_names: true)
41
41
  else
42
42
  {}
43
43
  end
@@ -49,4 +49,4 @@ class PigCI::Metric::Historical
49
49
  end
50
50
  end
51
51
 
52
- require 'pig_ci/metric/historial/change_percentage'
52
+ require "pig_ci/metric/historial/change_percentage"
@@ -2,14 +2,14 @@ class PigCI::Profiler
2
2
  attr_accessor :log_value, :log_file, :historical_log_file, :i18n_key
3
3
 
4
4
  def initialize(i18n_key: nil, log_file: nil, historical_log_file: nil)
5
- @i18n_key = i18n_key || self.class.name.underscore.split('/').last
5
+ @i18n_key = i18n_key || self.class.name.underscore.split("/").last
6
6
  @log_file = log_file || PigCI.tmp_directory.join("#{@i18n_key}.txt")
7
7
  @historical_log_file = historical_log_file || PigCI.tmp_directory.join("#{@i18n_key}.json")
8
8
  @log_value = 0
9
9
  end
10
10
 
11
11
  def setup!
12
- File.open(log_file, 'w') { |file| file.truncate(0) }
12
+ File.open(log_file, "w") { |file| file.truncate(0) }
13
13
  end
14
14
 
15
15
  def reset!
@@ -17,8 +17,8 @@ class PigCI::Profiler
17
17
  end
18
18
 
19
19
  def log_request!(request_key)
20
- File.open(log_file, 'a+') do |f|
21
- f.puts([request_key, log_value].join('|'))
20
+ File.open(log_file, "a+") do |f|
21
+ f.puts([request_key, log_value].join("|"))
22
22
  end
23
23
  end
24
24
 
@@ -36,6 +36,6 @@ class PigCI::Profiler
36
36
  end
37
37
  end
38
38
 
39
- require 'pig_ci/profiler/memory'
40
- require 'pig_ci/profiler/request_time'
41
- require 'pig_ci/profiler/database_request'
39
+ require "pig_ci/profiler/memory"
40
+ require "pig_ci/profiler/request_time"
41
+ require "pig_ci/profiler/database_request"
@@ -1,4 +1,4 @@
1
- require 'get_process_mem'
1
+ require "get_process_mem"
2
2
 
3
3
  class PigCI::Profiler::Memory < PigCI::Profiler
4
4
  def reset!
@@ -8,7 +8,7 @@ class PigCI::ProfilerEngine
8
8
  end
9
9
 
10
10
  def request_key?
11
- !@request_key.nil? && @request_key != ''
11
+ !@request_key.nil? && @request_key != ""
12
12
  end
13
13
 
14
14
  def request_captured?
@@ -37,4 +37,4 @@ class PigCI::ProfilerEngine
37
37
  end
38
38
  end
39
39
 
40
- require 'pig_ci/profiler_engine/rails'
40
+ require "pig_ci/profiler_engine/rails"
@@ -31,10 +31,13 @@ class PigCI::ProfilerEngine::Rails < ::PigCI::ProfilerEngine
31
31
  def precompile_assets!
32
32
  # From: https://github.com/rails/sprockets-rails/blob/e9ca63edb6e658cdfcf8a35670c525b369c2ccca/test/test_railtie.rb#L7-L13
33
33
  ::Rails.application.load_tasks
34
- ::Rake.application['assets:precompile'].execute
34
+ ::Rake.application["assets:precompile"].execute
35
35
  end
36
36
 
37
37
  def eager_load_rails!
38
+ # None of these methods will work pre-rails 5.
39
+ return unless ::Rails.version.to_f >= 5.0
40
+
38
41
  # Eager load rails to give more accurate memory levels.
39
42
  ::Rails.application.eager_load!
40
43
  ::Rails.application.routes.eager_load!
@@ -45,30 +48,32 @@ class PigCI::ProfilerEngine::Rails < ::PigCI::ProfilerEngine
45
48
  def make_blank_application_request!
46
49
  # Make a call to the root path to load up as much of rails as possible
47
50
  # Done within a timezone block as it affects the timezone.
48
- Time.use_zone('UTC') do
49
- ::Rails.application.call(::Rack::MockRequest.env_for('/'))
51
+ Time.use_zone("UTC") do
52
+ ::Rails.application.call(::Rack::MockRequest.env_for("/"))
50
53
  end
51
54
  end
52
55
 
53
56
  def attach_listeners!
54
- ::ActiveSupport::Notifications.subscribe 'start_processing.action_controller' do |_name, _started, _finished, _unique_id, payload|
57
+ ::ActiveSupport::Notifications.subscribe "start_processing.action_controller" do |_name, _started, _finished, _unique_id, payload|
55
58
  request_key_from_payload!(payload)
56
59
 
57
60
  profilers.each(&:reset!)
58
61
  end
59
62
 
60
- ::ActiveSupport::Notifications.subscribe 'sql.active_record' do |_name, _started, _finished, _unique_id, _payload|
61
- if request_key?
62
- profilers.select { |profiler| profiler.class == PigCI::Profiler::DatabaseRequest }.each(&:increment!)
63
+ ::ActiveSupport::Notifications.subscribe "sql.active_record" do |_name, _started, _finished, _unique_id, payload|
64
+ if request_key? && PigCI.enabled? && (!PigCI.ignore_cached_queries? || (PigCI.ignore_cached_queries? && !payload[:cached]))
65
+ profilers.select { |profiler| profiler.instance_of?(PigCI::Profiler::DatabaseRequest) }.each(&:increment!)
63
66
  end
64
67
  end
65
68
 
66
- ::ActiveSupport::Notifications.subscribe 'process_action.action_controller' do |_name, _started, _finished, _unique_id, _payload|
67
- profilers.each do |profiler|
68
- profiler.log_request!(request_key)
69
- end
69
+ ::ActiveSupport::Notifications.subscribe "process_action.action_controller" do |_name, _started, _finished, _unique_id, _payload|
70
+ if PigCI.enabled?
71
+ profilers.each do |profiler|
72
+ profiler.log_request!(request_key)
73
+ end
70
74
 
71
- request_captured!
75
+ request_captured!
76
+ end
72
77
  self.request_key = nil
73
78
  end
74
79
  end
data/lib/pig_ci/report.rb CHANGED
@@ -2,7 +2,7 @@ class PigCI::Report
2
2
  attr_accessor :historical_log_file, :i18n_key
3
3
 
4
4
  def initialize(historical_log_file: nil, i18n_key: nil, timestamp: nil)
5
- @i18n_key = i18n_key || self.class.name.underscore.split('/').last
5
+ @i18n_key = i18n_key || self.class.name.underscore.split("/").last
6
6
  @historical_log_file = historical_log_file || PigCI.tmp_directory.join("#{@i18n_key}.json")
7
7
  @timestamp = timestamp || PigCI.run_timestamp
8
8
  end
@@ -12,7 +12,7 @@ class PigCI::Report
12
12
  end
13
13
 
14
14
  def i18n_name
15
- I18n.t('.name', scope: i18n_scope, locale: PigCI.locale)
15
+ I18n.t(".name", scope: i18n_scope, locale: PigCI.locale)
16
16
  end
17
17
 
18
18
  def max_for(timestamp)
@@ -30,9 +30,9 @@ class PigCI::Report
30
30
  end
31
31
 
32
32
  def sorted_and_formatted_data_for(timestamp)
33
- data_for(timestamp)[@i18n_key.to_sym].sort_by do |data|
33
+ data_for(timestamp)[@i18n_key.to_sym].sort_by { |data|
34
34
  PigCI.report_row_sort_by(data)
35
- end.collect do |data|
35
+ }.collect do |data|
36
36
  self.class.format_row(data)
37
37
  end
38
38
  end
@@ -73,6 +73,6 @@ class PigCI::Report
73
73
  end
74
74
  end
75
75
 
76
- require 'pig_ci/report/memory'
77
- require 'pig_ci/report/request_time'
78
- require 'pig_ci/report/database_request'
76
+ require "pig_ci/report/memory"
77
+ require "pig_ci/report/request_time"
78
+ require "pig_ci/report/database_request"
@@ -10,6 +10,6 @@ class PigCI::Report::Memory < PigCI::Report
10
10
  end
11
11
 
12
12
  def self.bytes_in_a_megabyte
13
- @bytes_in_a_megabyte ||= BigDecimal(1_048_576)
13
+ @bytes_in_a_megabyte ||= BigDecimal("1_048_576")
14
14
  end
15
15
  end
@@ -1,5 +1,5 @@
1
1
  class PigCI::Summary; end
2
2
 
3
- require 'pig_ci/summary/ci'
4
- require 'pig_ci/summary/html'
5
- require 'pig_ci/summary/terminal'
3
+ require "pig_ci/summary/ci"
4
+ require "pig_ci/summary/html"
5
+ require "pig_ci/summary/terminal"
@@ -1,4 +1,4 @@
1
- require 'colorized_string'
1
+ require "colorized_string"
2
2
 
3
3
  class PigCI::Summary::CI < PigCI::Summary
4
4
  def initialize(reports:)
@@ -7,8 +7,8 @@ class PigCI::Summary::CI < PigCI::Summary
7
7
  end
8
8
 
9
9
  def call!
10
- puts ''
11
- puts I18n.t('pig_ci.summary.ci_start')
10
+ puts ""
11
+ puts I18n.t("pig_ci.summary.ci_start")
12
12
 
13
13
  over_threshold = false
14
14
  @reports.each do |report|
@@ -17,22 +17,22 @@ class PigCI::Summary::CI < PigCI::Summary
17
17
  end
18
18
 
19
19
  fail_with_error! if over_threshold
20
- puts ''
20
+ puts ""
21
21
  end
22
22
 
23
23
  private
24
24
 
25
25
  def fail_with_error!
26
- puts I18n.t('pig_ci.summary.ci_failure')
26
+ puts I18n.t("pig_ci.summary.ci_failure")
27
27
  Kernel.exit(2)
28
28
  end
29
29
 
30
30
  def print_report(report)
31
31
  max_and_threshold = [
32
32
  report.max_for(@timestamp).to_s,
33
- '/',
33
+ "/",
34
34
  report.threshold
35
- ].join(' ')
35
+ ].join(" ")
36
36
 
37
37
  if report.over_threshold_for?(@timestamp)
38
38
  puts "#{report.i18n_name}: #{ColorizedString[max_and_threshold].colorize(:red)}\n"