Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store project name in cache string #35 #38

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 20 additions & 19 deletions lib/debt_ceiling/analysis_caches/analysis_cache.rb
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
require_relative "git_note_adapter"
module DebtCeiling
class AnalysisCache
attr_reader :adapter

def self.commit_identifier(commit)
"debt_ceiling_#{commit}_#{config_string}"
end

def self.config_string
@config_string ||= config_hash_string + ArcheologicalDig::ARCHEOLOGY_RECORD_VERSION_NUMBER
end

def self.config_hash_string
Digest::SHA1.hexdigest(DebtCeiling.config_array.to_json)
end

def initialize(adapter=nil)
attr_reader :adapter, :project_name
ANALYSIS_CACHE_HASH_LENGTH = 6
def initialize(project_name, adapter=nil)
@adapter = adapter
@project_name = project_name
@adapter ||= auto_select_adapter
end

def get(commit)
text = adapter.get(self.class.commit_identifier(commit))
text = adapter.get(commit_identifier(commit))
if text
extract_record_from_text(text)
else
Expand All @@ -37,15 +26,15 @@ def set(commit, result)

def create_text_on_commit(commit, result)
text = <<-DATA
#{self.class.commit_identifier(commit)}
#{commit_identifier(commit)}
#{result.to_json}
DATA
adapter.set(self.class.commit_identifier(commit), text)
adapter.set(commit_identifier(commit), text)
end

def extract_record_from_text(text)
text.split("\n").each_cons(2).each do |comment, json|
return JSON.parse(json) if comment.match(AnalysisCache.config_string)
return JSON.parse(json) if comment.match(config_string)
end
end

Expand All @@ -60,5 +49,17 @@ def redis_if_available
Redis.new(host: host, port: port)
rescue LoadError
end

def commit_identifier(commit)
"DebtCeiling_#{project_name}_#{commit}_#{config_string}"
end

def config_string
@config_string ||= "#{config_hash_string}_#{ArcheologicalDig::ARCHEOLOGY_RECORD_VERSION_NUMBER}"
end

def config_hash_string
Digest::SHA1.hexdigest(DebtCeiling.config_array.to_json).slice(0...ANALYSIS_CACHE_HASH_LENGTH)
end
end
end
2 changes: 1 addition & 1 deletion lib/debt_ceiling/analysis_caches/git_note_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def set(key, result)
private

def actual_commit(key)
key.split('_')[2]
key.split('_')[2] #for now we sanitize underscores into dashes in project name
end

def read_note_on(commit)
Expand Down
25 changes: 15 additions & 10 deletions lib/debt_ceiling/archeological_dig.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,35 @@
require 'json'
module DebtCeiling
class ArcheologicalDig
ARCHEOLOGY_RECORD_VERSION_NUMBER = "v0" #increment for backward incompatible changes in record format
attr_reader :source_control, :records, :cache, :path, :opts

def self.dig_json_key(path)
project_name = File.expand_path(path).split('/').last
"DebtCeiling_#{project_name}_#{ARCHEOLOGY_RECORD_VERSION_NUMBER}"
end
ARCHEOLOGY_RECORD_VERSION_NUMBER = "v1" #increment for backward incompatible changes in record format
attr_reader :source_control, :records, :cache, :project_name, :path, :opts

def initialize(path='.', opts={})
@cache = AnalysisCache.new(opts[:analysis_cache])
@path = path
@opts = opts
@project_name = sanitized_project_name
@cache = AnalysisCache.new(project_name, opts[:analysis_cache])
@source_control = SourceControlSystem::Base.create
end

def process
DebtCeiling.load_configuration unless opts[:preconfigured]
@records = source_control.revisions_refs(path).map {|commit| process_commit(commit) }
cache.set(self.class.dig_json_key(path), records.to_json) if opts[:store_results]
cache.set(dig_json_key(path), records.to_json) if opts[:store_results]
self
end

private

def sanitized_project_name
name = opts[:project_name] || File.expand_path(path).split('/').last
name.gsub('_', '-')
end

def dig_json_key(path)
"DebtCeiling_#{project_name}_#{ARCHEOLOGY_RECORD_VERSION_NUMBER}"
end

def process_commit(commit)
cache.get(commit) { audit_commit(commit) }
end
Expand Down Expand Up @@ -57,7 +62,7 @@ def archeology_record(result, commit)
end

def default_record(result, commit)
{debt: result.total_debt, failed: !!result.failed_condition?, commit: commit}
{'debt' => result.total_debt, 'failed' => !!result.failed_condition?, 'commit' => commit}
end

end
Expand Down
2 changes: 1 addition & 1 deletion spec/archeological_dig_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
describe DebtCeiling::ArcheologicalDig do

CONFIG_STRING = "fake_config_string"
COMMIT_SHA_MSG = "debt_ceiling_#{COMMIT_SHA}_#{CONFIG_STRING}#{described_class::ARCHEOLOGY_RECORD_VERSION_NUMBER}\n {\"debt\":100,\"failed\":false,\"commit\":\"#{COMMIT_SHA}\"}\n"
COMMIT_SHA_MSG = "DebtCeiling_#{COMMIT_SHA}_#{CONFIG_STRING}#{described_class::ARCHEOLOGY_RECORD_VERSION_NUMBER}\n {\"debt\":100,\"failed\":false,\"commit\":\"#{COMMIT_SHA}\"}\n"

let(:fake_source_control) { double(DebtCeiling::SourceControlSystem::Git) }
let(:fake_audit) { double(DebtCeiling::Audit) }
Expand Down
37 changes: 8 additions & 29 deletions spec/debt_ceiling_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,36 @@
require 'debt_ceiling'

describe DebtCeiling do
let(:fake_audit) { double(DebtCeiling::Audit) }
before(:each) { allow(DebtCeiling::Audit).to receive(:new).and_return(fake_audit)}

it 'has failing exit status when debt_ceiling is exceeded' do
DebtCeiling.configure {|c| c.debt_ceiling = 0 }
expect(DebtCeiling.debt_ceiling).to eq(0)
expect_any_instance_of(DebtCeiling::Audit).to receive(:fail_test)
allow(fake_audit).to receive(:fail_test)
DebtCeiling.audit('.', preconfigured: true)
end

it 'has failing exit status when target debt reduction is missed' do
DebtCeiling.configure {|c| c.reduction_target =0; c.reduction_date = Time.now.to_s }
expect(DebtCeiling.debt_ceiling).to eq(nil)
expect_any_instance_of(DebtCeiling::Audit).to receive(:fail_test)
allow(fake_audit).to receive(:fail_test)
DebtCeiling.audit('.', preconfigured: true)
end

it 'has failing exit status when max debt per module is exceeded' do
DebtCeiling.configure {|c| c.max_debt_per_module =5 }
expect(DebtCeiling.debt_ceiling).to eq(nil)
expect_any_instance_of(DebtCeiling::Audit).to receive(:fail_test)
allow(fake_audit).to receive(:fail_test)
DebtCeiling.audit('.', preconfigured: true)
end

it 'has no failing exit status when in warn only mode' do
DebtCeiling.configure {|c| c.max_debt_per_module =5 }
expect(DebtCeiling.debt_ceiling).to eq(nil)
expect_any_instance_of(DebtCeiling::Audit).to receive(:failed_condition?).at_least(:once).and_return(true)
expect_any_instance_of(DebtCeiling::Audit).not_to receive(:fail_test)
allow(fake_audit).to receive(:failed_condition?).at_least(:once).and_return(true)
expect(fake_audit).not_to receive(:fail_test)
DebtCeiling.audit('.', preconfigured: true, warn_only: true)
end

it 'returns quantity of total debt' do
expect(DebtCeiling.audit('.').total_debt).to be > 5 # arbitrary non-zero amount
end

it 'adds debt for todos with specified value' do
todo_amount = 50
DebtCeiling.configure {|c| c.cost_per_todo = todo_amount }
expect(DebtCeiling.audit('spec/support/todo_example.rb', preconfigured: true).total_debt).to be todo_amount
end

it 'allows manual debt with TECH DEBT comment' do
expect(DebtCeiling.audit('spec/support/manual_example.rb', preconfigured: true).total_debt).to be 100 # hardcoded in example file
end

it 'allows manual debt with arbitrarily defined comment' do
DebtCeiling.configure {|c| c.manual_callouts += ['REFACTOR'] }
expect(DebtCeiling.audit('spec/support/manual_example.rb', preconfigured: true).total_debt).to be 150 # hardcoded in example file
end

it 'assigns debt for file length over ideal file size' do
DebtCeiling.configure {|c| c.ideal_max_line_count = 10; c.cost_per_line_over_ideal = 100 }
expect(DebtCeiling.audit('spec/support/long_file_example.rb', preconfigured: true).total_debt).to be 300 # hardcoded 13 lines long example file
end

end
2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

RSpec.configure do |config|
config.before { allow($stdout).to receive(:puts) }
config.after(:all) { DebtCeiling.audit unless ENV['SKIP'] }
at_exit { DebtCeiling.audit unless ENV['SKIP'] }
end