diff --git a/CHANGELOG.md b/CHANGELOG.md index dad5b29e..97513e31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### 5.2.0 + +* Send authors to the API + + https://github.com/KnapsackPro/knapsack_pro-ruby/pull/208 + +https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v5.1.2...v5.2.0 + ### 5.1.2 * Fix broken RSpec split by test examples feature when `SPEC_OPTS` is set in Queue Mode. Ignore `SPEC_OPTS` when generating test examples report for slow test files. diff --git a/lib/knapsack_pro.rb b/lib/knapsack_pro.rb index f15da72c..aaabf23a 100644 --- a/lib/knapsack_pro.rb +++ b/lib/knapsack_pro.rb @@ -55,6 +55,7 @@ require_relative 'knapsack_pro/adapters/spinach_adapter' require_relative 'knapsack_pro/allocator' require_relative 'knapsack_pro/queue_allocator' +require_relative 'knapsack_pro/mask_string' require_relative 'knapsack_pro/test_case_mergers/base_merger' require_relative 'knapsack_pro/test_case_mergers/rspec_merger' require_relative 'knapsack_pro/build_distribution_fetcher' diff --git a/lib/knapsack_pro/client/api/v1/build_distributions.rb b/lib/knapsack_pro/client/api/v1/build_distributions.rb index 3283a1b3..b32ccc1c 100644 --- a/lib/knapsack_pro/client/api/v1/build_distributions.rb +++ b/lib/knapsack_pro/client/api/v1/build_distributions.rb @@ -16,6 +16,8 @@ def subset(args) :node_index => args.fetch(:node_index), :ci_build_id => KnapsackPro::Config::Env.ci_node_build_id, :user_seat => KnapsackPro::Config::Env.masked_user_seat, + :build_author => KnapsackPro::RepositoryAdapters::GitAdapter.new.build_author, + :commit_authors => KnapsackPro::RepositoryAdapters::GitAdapter.new.commit_authors, } unless request_hash[:cache_read_attempt] diff --git a/lib/knapsack_pro/client/api/v1/queues.rb b/lib/knapsack_pro/client/api/v1/queues.rb index 4e7c5461..cb46a2f8 100644 --- a/lib/knapsack_pro/client/api/v1/queues.rb +++ b/lib/knapsack_pro/client/api/v1/queues.rb @@ -17,6 +17,8 @@ def queue(args) :node_index => args.fetch(:node_index), :node_build_id => KnapsackPro::Config::Env.ci_node_build_id, :user_seat => KnapsackPro::Config::Env.masked_user_seat, + :build_author => KnapsackPro::RepositoryAdapters::GitAdapter.new.build_author, + :commit_authors => KnapsackPro::RepositoryAdapters::GitAdapter.new.commit_authors, } if request_hash[:can_initialize_queue] && !request_hash[:attempt_connect_to_queue] diff --git a/lib/knapsack_pro/config/env.rb b/lib/knapsack_pro/config/env.rb index 1604a2ac..983c0c0e 100644 --- a/lib/knapsack_pro/config/env.rb +++ b/lib/knapsack_pro/config/env.rb @@ -67,7 +67,7 @@ def user_seat def masked_user_seat return unless user_seat - user_seat.gsub(/(?<=\w{2})[a-zA-Z]/, "*") + KnapsackPro::MaskString.call(user_seat) end def test_file_pattern diff --git a/lib/knapsack_pro/mask_string.rb b/lib/knapsack_pro/mask_string.rb new file mode 100644 index 00000000..567fbf96 --- /dev/null +++ b/lib/knapsack_pro/mask_string.rb @@ -0,0 +1,7 @@ +module KnapsackPro + class MaskString + def self.call(string) + string.gsub(/(?<=\w{2})[a-zA-Z]/, "*") + end + end +end diff --git a/lib/knapsack_pro/repository_adapters/git_adapter.rb b/lib/knapsack_pro/repository_adapters/git_adapter.rb index 4a249298..974fcfe0 100644 --- a/lib/knapsack_pro/repository_adapters/git_adapter.rb +++ b/lib/knapsack_pro/repository_adapters/git_adapter.rb @@ -14,8 +14,40 @@ def branches str_branches.split("\n") end + def commit_authors + authors = git_commit_authors + .split("\n") + .map { |line| line.strip } + .map { |line| line.split("\t") } + .map do |commits, author| + { commits: commits.to_i, author: KnapsackPro::MaskString.call(author) } + end + + raise if authors.empty? + + authors + rescue Exception + [] + end + + def build_author + author = KnapsackPro::MaskString.call(git_build_author.strip) + raise if author.empty? + author + rescue Exception + "no git " + end + private + def git_commit_authors + `git fetch --shallow-since "1 month ago" >/dev/null 2>&1 && git shortlog --summary --email --since "one month ago"` + end + + def git_build_author + `git log --format="%aN <%aE>" -1` + end + def working_dir dir = KnapsackPro::Config::Env.project_dir File.expand_path(dir) diff --git a/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb b/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb index 7a3b0eb8..99ded5ce 100644 --- a/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +++ b/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb @@ -8,6 +8,7 @@ let(:ci_build_id) { double } let(:masked_user_seat) { double } let(:test_files) { double } + let(:cache_read_attempt) { [false, true].sample } subject do described_class.subset( @@ -31,20 +32,9 @@ it 'does not send test_files among other params' do action = double - expect(KnapsackPro::Client::API::Action).to receive(:new).with({ - endpoint_path: '/v1/build_distributions/subset', - http_method: :post, - request_hash: { - fixed_test_suite_split: fixed_test_suite_split, - cache_read_attempt: cache_read_attempt, - commit_hash: commit_hash, - branch: branch, - node_total: node_total, - node_index: node_index, - ci_build_id: ci_build_id, - user_seat: masked_user_seat, - } - }).and_return(action) + expect(KnapsackPro::Client::API::Action).to receive(:new).with( + hash_including(request_hash: hash_excluding(:test_files)) + ).and_return(action) expect(subject).to eq action end end @@ -54,24 +44,22 @@ it 'sends test_files among other params' do action = double - expect(KnapsackPro::Client::API::Action).to receive(:new).with({ - endpoint_path: '/v1/build_distributions/subset', - http_method: :post, - request_hash: { - fixed_test_suite_split: fixed_test_suite_split, - cache_read_attempt: cache_read_attempt, - commit_hash: commit_hash, - branch: branch, - node_total: node_total, - node_index: node_index, - ci_build_id: ci_build_id, - user_seat: masked_user_seat, - test_files: test_files - } - }).and_return(action) + expect(KnapsackPro::Client::API::Action).to receive(:new).with( + hash_including(request_hash: hash_including(test_files: test_files)) + ).and_return(action) expect(subject).to eq action end end + + it "sends authors" do + action = double + + expect(KnapsackPro::Client::API::Action).to receive(:new).with( + hash_including(request_hash: hash_including(:build_author, :commit_authors)) + ).and_return(action) + + expect(subject).to eq action + end end describe '.last' do diff --git a/spec/knapsack_pro/client/api/v1/queues_spec.rb b/spec/knapsack_pro/client/api/v1/queues_spec.rb index 13b58df5..ace5a322 100644 --- a/spec/knapsack_pro/client/api/v1/queues_spec.rb +++ b/spec/knapsack_pro/client/api/v1/queues_spec.rb @@ -8,6 +8,8 @@ let(:test_files) { double } let(:node_build_id) { double } let(:masked_user_seat) { double } + let(:can_initialize_queue) { [false, true].sample } + let(:attempt_connect_to_queue) { [false, true].sample } subject do described_class.queue( @@ -65,5 +67,15 @@ expect(subject).to eq action end end + + it "sends authors" do + action = double + + expect(KnapsackPro::Client::API::Action).to receive(:new).with( + hash_including(request_hash: hash_including(:build_author, :commit_authors)) + ).and_return(action) + + expect(subject).to eq action + end end end diff --git a/spec/knapsack_pro/repository_adapters/git_adapter_spec.rb b/spec/knapsack_pro/repository_adapters/git_adapter_spec.rb index f592cb16..94d4cd0b 100644 --- a/spec/knapsack_pro/repository_adapters/git_adapter_spec.rb +++ b/spec/knapsack_pro/repository_adapters/git_adapter_spec.rb @@ -31,4 +31,76 @@ it { expect(subject.include?('master')).to be true } it { expect(subject.include?(circle_branch)).to be true } if ENV['CIRCLECI'] end + + describe '#build_author' do + it "returns the masked build author" do + allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_build_author).and_return( + "John Doe " + "\n" + ) + + subject = KnapsackPro::RepositoryAdapters::GitAdapter.new + + expect(subject.build_author).to eq 'Jo** Do* ' + end + + context "when the command raises an exception" do + it "returns the no-git author" do + allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_build_author).and_raise(Exception) + + subject = KnapsackPro::RepositoryAdapters::GitAdapter.new + + expect(subject.build_author).to eq "no git " + end + end + + context "when the command returns an empty string" do + it "returns the no-git author" do + allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_build_author).and_return("") + + subject = KnapsackPro::RepositoryAdapters::GitAdapter.new + + expect(subject.build_author).to eq "no git " + end + end + end + + describe '#commit_authors' do + it "returns the masked commit authors" do + allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_commit_authors).and_return([ + " 5\t3v0k4 \n", + " 10\tArtur Nowak \n", + " 2\tRiccardo \n", + " 3 \tshadre \n", + ].join("")) + + subject = KnapsackPro::RepositoryAdapters::GitAdapter.new + + expect(subject.commit_authors).to eq([ + { commits: 5, author: "3v0*4 " }, + { commits: 10, author: "Ar*** No*** " }, + { commits: 2, author: "Ri****** " }, + { commits: 3, author: "sh**** " }, + ]) + end + + context "when the authors command raises an exception" do + it "returns []" do + allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_commit_authors).and_raise(Exception) + + subject = KnapsackPro::RepositoryAdapters::GitAdapter.new + + expect(subject.commit_authors).to eq [] + end + end + + context "when the authors command returns an empty string" do + it "returns []" do + allow_any_instance_of(KnapsackPro::RepositoryAdapters::GitAdapter).to receive(:git_commit_authors).and_return("") + + subject = KnapsackPro::RepositoryAdapters::GitAdapter.new + + expect(subject.commit_authors).to eq [] + end + end + end end